• 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. }

  • 相关阅读:
    Liinux——(网络)socket编程
    数据库-MySQL-基础(6)- DCL
    10-SRCNN-使用CNN实现超分辨成像
    6-8 最宽层次结点数 分数 10
    机器学习——多层感知机
    JVM学习-- JVM调优
    Linux NetCore下Pdf转图片 内存溢出
    算法day 14 第六章二叉树
    upload-labs1-21关文件上传通关手册
    Linux音频系统编程之芯片平台适配功放Codec Driver解读
  • 原文地址:https://blog.csdn.net/ashbringer233/article/details/133978456