[关闭]
@y20070316 2017-04-24T05:44:04.000000Z 字数 4086 阅读 1008

XSY 1903 - Circle of Stones & XSY 1606 - 大包子的绕口令

题目精选 KMP FFT


题意

  桌子上有 个石头围成一个环。每个石头都有一种颜色。每种颜色可以由小写英文字母表示,所以总共有 种颜色。不同的石头可能有相同的颜色。

  如果每一对的石头都是不同颜色的,则称这 个石头构成的环是美丽的。两个石头是相邻的充要条件是这两个石头中间没有其它石头。例如: 号和 号是相邻的, 号和 号是相邻的,……, 号和 号是相邻的。

  现在,你可以从这 个石头中拿走一段连续的石头(可以为空),且你只能拿一次。

  你的任务是对于每个 ,判断是否存在一种取石头的方案,使得在拿走 个连续的石头后,剩下的 个石头构成的环是美丽的。

  

分析

  现在的问题是是否能删去连续的 个, ,使得剩下的 个两两不同。那么,问题等价于能否保留连续的 个, ,它们两两不同。

  首先将数组 进行倍长。

  我们考虑到,若在原数组中 中,存在一个位置 ,则我们保留的区间一定不同时覆盖 。按照 ,将原数组分段。那么,考虑每个段内可以保留的情况,然后并起来即可。对于一个段,长度为 ,那么段内保留的长度上限一定是 的,所以总共的保留是 的。

  对于一个段,它的任意两个相邻元素不同。我们考虑能否保留连续的 个。直接想能否保留不好想,我们考虑怎样才不能保留连续的 个。那么要求 ,所以 是原串的一个覆盖串。我们只要找到所有的覆盖串,就能确定所有不能覆盖的了,反之就是能覆盖的。

分析2

  我们记
  考虑一个区间 什么时候合法。合法,当且仅当 ,且 ,它可以贡献到
  发现 是单调递增的,所以只需要对连续的一段,对所有 ,贡献到
  我们构造式子 ,那么,一个位置 有解,当且仅当
  如何快速求 ?我们考虑将一个 进行翻转,然后用 FFT 解决。

  为什么分析2能更巧妙的化为分析1?
  首先,发现 单调递增,这相当于进行分段。
  然后,我们 FFT 做法的本质是用优化暴力,但实际上有着更多的特性:循环节。从而有了分析1。

  这种做法在 xsy1903 一题25分 , xsy1606 一题50分。

实现

KMP:
int 写成了 char ,调了好久。

  1. #include <cstdio>
  2. #include <cstring>
  3. #define F(i,a,b) for (int i=(a);i<=(b);i++)
  4. const int N=2097152;
  5. const int INF=0x7fffffff;
  6. int n,n2;
  7. char s[N];
  8. int v[N];
  9. int len;
  10. int nx[N];
  11. char ans[N];
  12. int main(void) {
  13. #ifndef ONLINE_JUDGE
  14. freopen("sdchr.in","r",stdin);
  15. freopen("sdchr.out","w",stdout);
  16. #endif
  17. F(c,1,INF) {
  18. memset(s,0,sizeof s);
  19. if (scanf("%s",s+1)==EOF) break;
  20. n=strlen(s+1);
  21. n2=n+n;
  22. F(i,n+1,n2) s[i]=s[i-n];
  23. memset(v,0,sizeof v);
  24. F(x,1,n2) {
  25. int d=x-1;
  26. int y=x; while (y+1<=n2&&s[y]!=s[y+1]) y++;
  27. len=y-x+1;
  28. int j=nx[1]=0;
  29. F(i,2,len) {
  30. while (j>0&&s[d+j+1]!=s[d+i]) j=nx[j];
  31. if (s[d+j+1]==s[d+i]) j++;
  32. nx[i]=j;
  33. }
  34. F(i,1,len) v[i]++;
  35. for (int i=len;nx[i]>0;i=nx[i])
  36. v[(len-nx[i])+1]--;
  37. x=y;
  38. memset(nx,0,sizeof(nx[0])*len);
  39. len=0;
  40. }
  41. memset(ans,0,sizeof ans);
  42. F(i,0,n-1)
  43. if (v[n-i]>0)
  44. ans[i]='1';
  45. else ans[i]='0';
  46. ans[n]='\n';
  47. printf("Case %d: %s",c,ans);
  48. }
  49. return 0;
  50. }

FFT:

  1. #include <cstdio>
  2. #include <iostream>
  3. #include <cstring>
  4. #include <cmath>
  5. #include <algorithm>
  6. using namespace std;
  7. #define F(i,a,b) for (int i=(a);i<=(b);i++)
  8. const int N=4194304;
  9. const int INF=0x7fffffff;
  10. const double PI=acos(-1);
  11. int n;
  12. int a[N];
  13. int n2;
  14. int b[N],s[N];
  15. int bit,len,rev[N];
  16. struct CP {
  17. double x,y;
  18. inline CP(double _x=0,double _y=0):x(_x),y(_y){}
  19. friend inline CP operator + (CP a,CP b) {
  20. return CP(a.x+b.x,a.y+b.y);
  21. }
  22. friend inline CP operator - (CP a,CP b) {
  23. return CP(a.x-b.x,a.y-b.y);
  24. }
  25. friend inline CP operator * (CP a,CP b) {
  26. return CP(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);
  27. }
  28. }A[N],A2[N],A3[N],B[N],B2[N],B3[N],R[N];
  29. char ans[N];
  30. inline int Read(int &n,int *a) {
  31. static char s[N]; if (scanf("%s",s+1)==EOF) return 0;
  32. n=strlen(s+1); F(i,1,n) a[i]=s[i]-'a'+1; return 1;
  33. }
  34. void FFT(CP *a,int bit,int n,int kd) {
  35. F(i,0,n-1) if (i<rev[i]) swap(a[i],a[rev[i]]);
  36. for (int i=2;i<=n;i<<=1) {
  37. CP wn(cos(2*PI/i),kd*sin(2*PI/i));
  38. for (int j=0;j<n;j+=i) {
  39. CP w(1,0);
  40. F(k,0,i/2-1) {
  41. CP x=a[j+k],y=w*a[j+k+i/2];
  42. a[j+k]=x+y,a[j+k+i/2]=x-y;
  43. w=w*wn;
  44. }
  45. }
  46. }
  47. if (kd==-1) F(i,0,n-1) a[i].x=round(a[i].x/n),a[i].y=0;
  48. }
  49. int main(void) {
  50. #ifndef ONLINE_JUDGE
  51. freopen("sdchr.in","r",stdin);
  52. freopen("sdchr.out","w",stdout);
  53. #endif
  54. F(c,1,INF) {
  55. if (!Read(n,a)) break;
  56. n2=n+n; F(i,n+1,n2) a[i]=a[i-n];
  57. F(i,2,n2) b[i]=(a[i]==a[i-1]),s[i]=s[i-1]+b[i];
  58. fill(ans,ans+(n-2)+1,'0'); ans[n-1]='1',ans[n]='\n';
  59. F(x,2,n2) {
  60. int y=x; while (y+1<=n2&&s[y+1]==s[x]) y++;
  61. int length=y-x+1;
  62. for (bit=0,len=1;len<=(length-1)+(length-1);bit++,len<<=1);
  63. F(i,0,len-1) rev[i]=rev[i>>1]>>1|(i&1)<<(bit-1);
  64. F(i,x,y) {
  65. int loc=i-x;
  66. A[loc]=B[loc]=CP(a[i]);
  67. A2[loc]=B2[loc]=CP(a[i]*a[i]);
  68. A3[loc]=B3[loc]=CP(a[i]*a[i]*a[i]);
  69. }
  70. reverse(B,B+length);
  71. reverse(B2,B2+length);
  72. reverse(B3,B3+length);
  73. FFT(A,bit,len,1);
  74. FFT(A2,bit,len,1);
  75. FFT(A3,bit,len,1);
  76. FFT(B,bit,len,1);
  77. FFT(B2,bit,len,1);
  78. FFT(B3,bit,len,1);
  79. F(i,0,len-1)
  80. R[i]=A3[i]*B[i]+CP(-2)*A2[i]*B2[i]+A[i]*B3[i];
  81. FFT(R,bit,len,-1);
  82. F(i,0,len-1) if (R[i].x>0) {
  83. int loc=n-(i-(length-1)+1);
  84. if (0<=loc&&loc<=n-2)
  85. ans[loc]='1';
  86. }
  87. memset(A,0,sizeof(A[0])*len);
  88. memset(A2,0,sizeof(A2[0])*len);
  89. memset(A3,0,sizeof(A2[0])*len);
  90. memset(B,0,sizeof(B[0])*len);
  91. memset(B2,0,sizeof(B2[0])*len);
  92. memset(B3,0,sizeof(A2[0])*len);
  93. memset(R,0,sizeof(R[0])*len);
  94. x=y;
  95. }
  96. printf("Case %d: ",c);
  97. fwrite(ans,1,n+1,stdout);
  98. memset(a+1,0,sizeof(a[0])*n2);
  99. memset(b+1,0,sizeof(b[0])*n2);
  100. memset(s+1,0,sizeof(s[0])*n2);
  101. }
  102. return 0;
  103. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注