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

  • 相关阅读:
    《Java编程思想》读书笔记(三)
    【shell】shell 数组处理
    React Hook用法详解(6个常见hook)
    Mysql 45讲学习笔记(三十八)Memory引擎
    二造考生必看|巩固优选题库助力考生最后冲刺
    Redis基础入门教程 - 概览
    产品经理需要掌握哪些产品专业知识?
    Laravel :如何将Excel文件导入数据库
    Java中的volatile
    知识积累:PageHelper分页问题,页码小于总页数和大于总页数返回数据问题,PageHelper分页失效
  • 原文地址:https://blog.csdn.net/ashbringer233/article/details/133978456