• C. You Are So Beautiful Codeforces Round 905 (Div. 2)


    Problem - C - Codeforces

    题目大意:有一个长度为n的数组a,问有多少个子串[l,r],满足这个子串作为子序列只在a中出现过一次

    1<=n<=1e5;1<=a[i]<=1e9

    思路:我们发现对于从1开始的连续区间,答案都是非递减的,所以我们考察每添加一个数字,答案怎么变化,并不会影响前面的答案。

            那么假如我们当前新添了一个数a[r],那么新增的合法答案计数就是a[r]为区间右端点的合法子串,也就是看1到r中有多少个l满足[l,r]是合法区间,我们发现,对于前面的一个数a[i],如果它出现了多次,那么只有第一次出现时作为区间左端点才是合法的,在后面出现时那个数都可以被第一次出现的那个数替代,所以每个位置的数的贡献也就是在它前面第一次出现的数的数量,那么每个相同的数的贡献,也就是在最后出现的那个位置之前有多少第一次出现的数。

            要统计答案我们首先记录每个数最后一次出现的位置las[i],然后从左往右遍历数组,记录第一次出现的数的数量,然后如果当前数已经在这个数最后一次出现的位置,就统计这个数的贡献。

    1. //#include<__msvc_all_public_headers.hpp>
    2. #include
    3. using namespace std;
    4. typedef long long ll;
    5. const ll MOD = 1e9 + 7;
    6. const int N = 1e5 + 5;
    7. int n;
    8. int a[N];
    9. void init()
    10. {
    11. }
    12. void solve()
    13. {
    14. map<int, int>las;
    15. cin >> n;
    16. init();
    17. for (int i = 1; i <= n; i++)
    18. {
    19. cin >> a[i];
    20. las[a[i]] = i;//记录每个数字最后一次出现的次数
    21. }
    22. ll ans = 0;
    23. ll cnt = 0;
    24. set<int>vis;
    25. for (int i = 1; i <= n; i++)
    26. {
    27. if (vis.find(a[i]) == vis.end())
    28. {//第一次出现这个数字
    29. cnt++;//记录有多少个第一次出现的
    30. vis.insert(a[i]);
    31. }
    32. if (las[a[i]] == i)
    33. {//当前数字是最后一次出现的位置,统计贡献
    34. ans += cnt;
    35. }
    36. }
    37. cout << ans;
    38. cout << '\n';
    39. }
    40. int main()
    41. {
    42. ios::sync_with_stdio(false);
    43. cin.tie(0);
    44. int t;
    45. cin >> t;
    46. //t = 1;
    47. while (t--)
    48. {
    49. solve();
    50. }
    51. return 0;
    52. }

  • 相关阅读:
    English语法_介词搭配
    EMQX安装与使用文档
    [ROS 系列学习教程] 建模与仿真 - 使用 Arbotix 控制机器人
    04-React路由5版本(高亮, 嵌套, 参数传递... )
    【SQL刷题】Day11----SQL通配符专项练习
    Python 学习之路
    NewStarCTF2023week4-R通大残(RGB通道隐写)
    JDBC详解
    Oracle 数据库查询下级_Oracle数据库之递归查询
    离散数学 ---- 图论基础 --- 图的引入,表示与分类
  • 原文地址:https://blog.csdn.net/ashbringer233/article/details/133978456