codeforces Educational Codeforces Round 65 (补完)

向右看齐 2023-10-11 10:11 167阅读 0赞

C News Distribution

并查集水题

D Bicolored RBS

括号匹配问题,如果给出的括号序列nesting depth为n,那么最终可以分成两个nesting depth为n / 2的序列。
在进行匹配的时候,如果当前栈中的左括号大于等于 n / 2,那么剩下的括号就要进行标记,最终标记和不标记的分成两个部分。

E Range Deleting

对一个序列去掉一个区间范围内的数字,使得剩下的序列是一个非降序的序列。
这题是一道较好的思维题。
首先可以预处理出1到\(pref\),只保留\([1,pref]\)内的数字,序列是非降序的;也可以预处理出\(suf\)到\(x\),保留\([suf,x]\)内的数字,序列是非降序的。
然后可以发现,如果去掉\([l,r]\)满足条件,那么去掉\([l,r+1],[l,r+2],…,[l,x]\)也一定是满足条件的。
可以枚举\(l\),枚举的范围是\([1,pref+1]\),\(pref+1\)是因为\([1,pref]\)的序列都是有序的,所以去掉\(pref+1\)也是有序的;对于每一个\(l\),要找出满足条件的\(r\)的数量;
因为去掉了\(l\)到某个数字,前面剩下的数字就是\([1,l-1]\),那么\(r\)满足的条件就是首先要大于等于\(suf\),大于等于\(l\),然后还要满足在\([1,l-1]\)当中出现的最大的数字的最后一个下标之前,这个数字没有出现过,换个角度,假设\([1,l-1]\)当中出现的最大的数字的最后一个下标是\(ind\),那么\(r\)的最小值就是\(max(a[1],….,a[ind])+1\),于是\(r\)的最小值就由之前的3个条件共同求出,满足条件的\(r\)的个数就分为两种情况:
1.\(l == r\),那么就有\(x - r + 1\)种;
2.\(l != r\),那么就有\(x - r + 2\)种,因为\(r\)是可以保留在序列当中的,所以可以去掉的范围是\([r-1,x]\),也就是说去掉\([l,r-1]\)这个区间也是满足条件的。

代码:

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <algorithm>
  4. #include <vector>
  5. #include <set>
  6. using namespace std;
  7. typedef long long ll;
  8. const int inf = 0x3f3f3f3f;
  9. const int N = 1e6 + 10;
  10. vector<int> G[N];
  11. set<int> s;
  12. int pre[N],sub[N];
  13. int a[N];
  14. bool L[N],R[N];
  15. int main()
  16. {
  17. int n,x;
  18. scanf("%d%d",&n,&x);
  19. for (int i = 1;i <= n;i++)
  20. {
  21. scanf("%d",&a[i]);
  22. s.insert(a[i]);
  23. }
  24. if (x == 1)
  25. {
  26. puts("1");
  27. return 0;
  28. }
  29. pre[0] = -inf;
  30. for (int i = 1;i <= n;i++)
  31. {
  32. pre[i] = max(pre[i-1],a[i]);
  33. }
  34. sub[n+1] = inf;
  35. for (int i = n;i >= 1;i--)
  36. {
  37. sub[i] = min(sub[i+1],a[i]);
  38. }
  39. for (int i = 1;i <= n;i++)
  40. {
  41. G[a[i]].push_back(i);
  42. }
  43. int pref,suf;
  44. L[1] = 1;
  45. for (int i = 2;i <= x;i++)
  46. {
  47. if (G[i].empty())
  48. {
  49. L[i] = L[i-1];
  50. }
  51. else
  52. {
  53. int p = G[i][0];
  54. int x = sub[p];
  55. if (x < i)
  56. {
  57. L[i] = 0;
  58. }
  59. else
  60. {
  61. L[i] = L[i-1];
  62. }
  63. }
  64. }
  65. R[x] = 1;
  66. for (int i = x - 1;i >= 1;i--)
  67. {
  68. if (G[i].empty())
  69. {
  70. R[i] = R[i+1];
  71. }
  72. else
  73. {
  74. int sz = G[i].size();
  75. int p = G[i][sz-1];
  76. int x = pre[p];
  77. if (x > i)
  78. {
  79. R[i] = 0;
  80. }
  81. else
  82. {
  83. R[i] = R[i+1];
  84. }
  85. }
  86. }
  87. for (int i = 1;i <= x;i++)
  88. {
  89. if (L[i]) pref = i;
  90. }
  91. for (int i = x;i >= 1;i--)
  92. {
  93. if (R[i]) suf = i;
  94. }
  95. ll ans = 0;
  96. for (int i = 1;i <= x;i++)
  97. {
  98. if (i == 1)
  99. {
  100. for (int j = 1;j <= x;j++)
  101. {
  102. if (R[j+1])
  103. {
  104. ans += x - j + 1;
  105. //printf("%d *\n",x - j + 1);
  106. break;
  107. }
  108. }
  109. }
  110. else
  111. {
  112. if (!L[i-1]) break;
  113. int l = i-1;
  114. if (l < (*s.begin()) || l > (*--s.end()))
  115. {
  116. int tmp = max(l + 1,suf);
  117. if (tmp == l + 1)
  118. {
  119. ans += x - tmp + 1;
  120. }
  121. else
  122. {
  123. ans += x - tmp + 2;
  124. //printf("%d *\n",x - tmp + 2);
  125. }
  126. }
  127. else
  128. {
  129. if (G[l].empty())
  130. {
  131. int xx = *--s.lower_bound(l);
  132. int sz = G[xx].size();
  133. int p = G[xx][sz-1];
  134. int tmp = max(pre[p] + 1,suf);
  135. tmp = max(l + 1,tmp);
  136. if (tmp == l + 1)
  137. {
  138. ans += x - tmp + 1;
  139. }
  140. else
  141. {
  142. ans += x - tmp + 2;
  143. }
  144. }
  145. else
  146. {
  147. int sz = G[l].size();
  148. int p = G[l][sz-1];
  149. int tmp = max(pre[p] + 1,suf);
  150. if (tmp == l + 1)
  151. {
  152. ans += x - tmp + 1;
  153. }
  154. else
  155. {
  156. ans += x - tmp + 2;
  157. }
  158. }
  159. }
  160. }
  161. }
  162. printf("%lld\n",ans);
  163. return 0;
  164. }

F Scalar Queries

题意:

有一个数组\(a\),里面的数字两两不同,\(f(l,r)\)表示选出下标从\(l\)到\(r\)的数字,然后排序,排序之后的数组为\(b\),\(\sum_{i = 1}^{r - l + 1}b_i * i\)。
需要求每一个\(f(l,r)\)的和。

思路:

又是一道很好的思维题。
可以转化为求每一个数字对最终答案的贡献。
假设\(low(l,r,a[i])\)表示在区间\([l,r]\)内小于\(a[i]\)的数字,那么\(a[i]\)对于\((l,r)\)的贡献就是\(a[i] * low(l,r,a[i])+1\)。
\(low(l,r,a[i])+1\)就相当于\(a[i]\)在\((l,r)\)内的rank。
这个rank又转化为每一个小于\(a[i]\)的数字出现的次数之和。
首先对于\(a_i\)本身,它自己出现的次数是\(i * (n - i - 1)\);
然后对于\(a_j < a_i,j < i\)的数字,它的出现次数是\(j * (n - i + 1)\);
对于\(a_j < a_i,j > i\)的数字,它的出现次数是\(i * (n - j + 1)\);
如上三个数字相加,假设为\(sum\),那么\(sum * a_i\)就是\(a_i\)对答案的贡献。
对于小于某个数字的所有数字出现的位置,可以用树状数组求前缀和。大的也同理。
又出现了\(int * int\) 爆\(int\) 的问题!!!

代码:

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <algorithm>
  4. using namespace std;
  5. typedef long long ll;
  6. typedef pair<int,int> pii;
  7. const int N = 5e5 + 10;
  8. const ll mod = 1000000000LL + 7;
  9. ll c[N],d[N];
  10. int n;
  11. int lowbit(int x)
  12. {
  13. return x&(-x);
  14. }
  15. void addl(int x,int y)
  16. {
  17. for (int i = x;i <= n;i += lowbit(i)) c[i] += y;
  18. }
  19. void addr(int x,int y)
  20. {
  21. for (int i = x;i <= n;i += lowbit(i)) d[i] += y;
  22. }
  23. ll getlsum(int x)
  24. {
  25. ll ans = 0;
  26. for (int i = x;i >= 1;i -= lowbit(i))
  27. {
  28. ans += c[i];
  29. ans %= mod;
  30. }
  31. return ans;
  32. }
  33. ll getrsum(int x)
  34. {
  35. ll ans = 0;
  36. for (int i = x;i >= 1;i -= lowbit(i))
  37. {
  38. ans += d[i];
  39. ans %= mod;
  40. }
  41. return ans;
  42. }
  43. pii a[N];
  44. int main()
  45. {
  46. scanf("%d",&n);
  47. for (int i = 1;i <= n;i++)
  48. {
  49. scanf("%d",&a[i].first);
  50. a[i].second = i;
  51. }
  52. sort(a+1,a+1+n);
  53. ll ans = 0;
  54. for (int i = 1;i <= n;i++)
  55. {
  56. ll x = getlsum(a[i].second);
  57. ll tmp = 0;
  58. tmp += x * (n-a[i].second+1);
  59. tmp %= mod;
  60. ll y = getrsum(n-a[i].second+1);
  61. tmp += y * a[i].second;
  62. tmp %= mod;
  63. tmp += 1LL * a[i].second * (n-a[i].second + 1);
  64. tmp %= mod;
  65. ans += tmp * a[i].first;
  66. ans %= mod;
  67. addl(a[i].second,a[i].second);
  68. addr(n-a[i].second + 1,n-a[i].second+1);
  69. }
  70. ans += mod;
  71. printf("%lld\n",ans % mod);
  72. return 0;
  73. }

转载于:https://www.cnblogs.com/kickit/p/10897606.html

发表评论

表情:
评论列表 (有 0 条评论,167人围观)

还没有评论,来说两句吧...

相关阅读