[关闭]
@AkamemakA 2022-07-21T12:06:10.000000Z 字数 1440 阅读 132

Atcoder 题解

Atcoder Beginner Contest 260 problem E 题解


题目链接:点我

题目大意

给定对数和一个整数,第对数包含两个数。定义一个长度为的序列是好的,当且仅当满足:是数列的一段连续子序列,且对数中每一对数都至少有一个数出现在中。

定义函数,表示长度为的满足以上定义的数列的个数。

要求输出

第一行输入,以后行,每行两个数

样例输入1

  1. 3 5
  2. 1 3
  3. 1 4
  4. 2 5

样例输出

  1. 0 1 3 2 1

样例解释1

下面是所有的好的数列:

样例输入2

  1. 1 2
  2. 1 2

样例输出2

  1. 2 1

样例输入3

  1. 5 9
  2. 1 5
  3. 1 7
  4. 5 6
  5. 5 8
  6. 2 6

样例输出3

  1. 0 0 1 2 4 4 3 2 1

数据范围


解析

我们可以对每一个数(),添加一个属性:表示数出现在那些编号的数对中。例如,在样例1中,数出现在了第和第二对数中,则{}。因为会有多个数,所以我们用来存储。

容易想到,如果一段数列中,所有的数的中,如果包含了,那么说明这段序列一定是好的。另外,不难想到,如果一段序列是好的,那么这段序列向外扩展出的序列也一定是好的。

因此,这道题的思路就像滑动窗口一般。先定下窗口左端,然后枚举窗口右端。若某时某刻,找到了一段好的序列,那么这之后的序列一定都是好的序列。

而对于答案统计,我们可以用差分来实现。

代码实现

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int N=2e5+5;
  4. int n,m;
  5. int a[N],b[N];
  6. int cnt[N],ans[N]; //cnt[j]表示在一段序列中,数i的v[i]中的元素j出现的个数
  7. vector<int>v[N]; //v[i]
  8. int main()
  9. {
  10. cin>>n>>m;
  11. for(int i=1;i<=n;i++)
  12. cin>>a[i]>>b[i];
  13. for(int i=1;i<=n;i++){
  14. v[a[i]].push_back(i);
  15. v[b[i]].push_back(i);
  16. }
  17. int cntn=n; //cntn表示在寻找好的序列时,剩余未出现的数对的个数
  18. for(int i=1,j=1;i<=m;i++){ //i为左端点
  19. while(j<=m&&cntn){ //将右端点j向右移
  20. for(auto &c:v[j]){//枚举v[j]并标记
  21. if(cnt[c]==0) cntn--; //若数对c没有出现过,则标记
  22. cnt[c]++;
  23. }
  24. j++;
  25. }
  26. if(cntn) break; //cntn=0,说明找到了好的序列,则更新nas数组
  27. //如果cntn!=0,那么说明右端点找到了最后都没有找到好的序列,那么左端点再向右移也不可能再找到了,就退出循环
  28. ans[j-i]++;ans[m+1-i+1]--; //更新答案
  29. for(auto &c:v[i]){
  30. cnt[c]--;
  31. if(cnt[c]==0)cntn++;
  32. }//将左端点右移,并将之前统计过的数还原
  33. }
  34. for(int i=1;i<=m;i++){
  35. ans[i]+=ans[i-1];
  36. cout<<ans[i]<<" ";
  37. }
  38. return 0;
  39. }

完结撒花~

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注