暴走的图灵机
2016-04-11 14:03
363 查看
题目描述
做法
m代表T串的长度。一个显然的做法是设g[i]表示i次操作后左手串所包含T串的个数。
则g[i]=g[i-2]+g[i-1]+c
其中c表示跨越中间线(即隔开i-2和i-1次操作后左手串的那条线)的所有串中T串的数量。
设f[i]表示i次操作后左手串的长度。
仔细观察发现,当f[i-2]和f[i-1]都不小于m后,c的循环节为2。
然后先暴力找到最早的id满足f[id]比2m-2大,然后矩阵乘法。
#include<cstdio> #include<algorithm> #include<stack> #define fo(i,a,b) for(i=a;i<=b;i++) #define fd(i,a,b) for(i=a;i>=b;i--) using namespace std; typedef long long LL; const int maxn=100+10,maxm=50000+10; int f[maxn],g[maxn],next[maxm]; bool pre[maxn][maxm],suc[maxn][maxm],s[maxm],ss[maxm]; int i,j,k,l,t,n,m,p,ans,id,c1,c2; stack<int> sta; char ch; struct matrix{ int a[5][5]; }; matrix operator *(matrix a,matrix b){ matrix c; int i,j,k; fo(i,0,4) fo(j,0,4) c.a[i][j]=0; fo(k,1,4) fo(i,1,4) fo(j,1,4) c.a[i][j]=(c.a[i][j]+(LL)a.a[i][k]*b.a[k][j]%p)%p; return c; } matrix a,dis,c,one,tt; int kmp(bool *a,int n,bool *b,int m){ int ans=0,i,j; j=0; next[1]=0; fo(i,2,m){ while (j&&b[j+1]!=b[i]) j=next[j]; if (b[j+1]==b[i]) j++; next[i]=j; } j=0; fo(i,1,n){ while (j&&b[j+1]!=a[i]) j=next[j]; if (b[j+1]==a[i]) j++; if (j==m){ ans=(ans+1)%p; j=next[j]; } } return ans; } matrix quicksortmi(matrix x,int y){ if (y==0) return one; tt=quicksortmi(x,y/2); tt=tt*tt; if (y%2) tt=tt*x; return tt; } int main(){ scanf("%d%d%d",&n,&m,&p); ch=getchar(); while (ch!='0'&&ch!='1') ch=getchar(); s[1]=ch-'0'; fo(i,2,m){ ch=getchar(); s[i]=ch-'0'; } f[0]=f[1]=1; fo(i,2,n){ if (f[i-1]+f[i-2]>1000000) f[i]=1000000;else f[i]=f[i-1]+f[i-2]; if (f[i]>m*5) break; } pre[0][1]=suc[0][1]=0; pre[1][1]=suc[1][1]=1; if (m==1){ if (s[1]) g[1]=1%p;else g[0]=1%p; } fo(i,2,n){ g[i]=(g[i-2]+g[i-1])%p; if (f[i-1]<m){ fo(j,1,f[i-2]) ss[j]=pre[i-2][j]; fo(j,1,f[i-1]) ss[f[i-2]+j]=pre[i-1][j]; g[i]=(g[i]+kmp(ss,f[i],s,m))%p; fo(j,1,min(f[i],m-1)) pre[i][j]=ss[j]; t=0; fo(j,max(f[i]-m+2,1),f[i]) suc[i][++t]=ss[j]; } else if (f[i-2]<m){ fo(j,1,f[i-2]) ss[j]=pre[i-2][j]; fo(j,1,m-1) ss[f[i-2]+j]=pre[i-1][j]; g[i]=(g[i]+kmp(ss,f[i-2]+m-1,s,m))%p; fo(j,1,m-1) pre[i][j]=ss[j]; fo(j,1,m-1) suc[i][j]=suc[i-1][j]; } else{ fo(j,1,m-1) ss[j]=suc[i-2][j]; fo(j,1,m-1) ss[j+m-1]=pre[i-1][j]; g[i]=(g[i]+kmp(ss,2*m-2,s,m))%p; fo(j,1,m-1) pre[i][j]=pre[i-2][j]; fo(j,1,m-1) suc[i][j]=suc[i-1][j]; id=i; break; } } if (id==n) printf("%d\n",g ); else{ fo(i,1,m-1) ss[i]=suc[id-1][i]; fo(i,1,m-1) ss[i+m-1]=pre[id-2][i]; c1=kmp(ss,2*m-2,s,m); fo(i,1,m-1) ss[i+m-1]=pre[id-1][i]; c2=kmp(ss,2*m-2,s,m); a.a[1][1]=g[id-1]; a.a[1][2]=g[id]; a.a[1][3]=c1; a.a[1][4]=c2; fo(i,0,4) a.a[0][i]=0; fo(i,2,4) fo(j,0,4) a.a[i][j]=0; dis.a[1][1]=dis.a[2][1]=dis.a[3][1]=1; dis.a[2][2]=2; dis.a[1][2]=dis.a[3][2]=dis.a[4][2]=1; dis.a[3][3]=dis.a[4][4]=1; //dis.a[4][1]=dis.a[1][3]=dis.a[2][3]=dis.a[4][3]=dis.a[1][4]=dis.a[2][] fo(i,1,4) one.a[i][i]=1; /*c=a*quicksortmi(dis,(n-id)/2); if ((n-id)%2) printf("%d\n",((c.a[1][1]+c.a[1][2])%p+c1)%p);else printf("%d\n",c.a[1][2]);*/ /*c=a*quicksortmi(dis,(n-id+1)/2); if ((n-id)%2) printf("%d\n",c.a[1][1]);else printf("%d\n",c.a[1][2]);*/ /*fo(i,1,(n-id+1)/2) a=a*dis; if ((n-id)%2) printf("%d\n",a.a[1][1]);else printf("%d\n",a.a[1][2]);*/ /*tt=one; fo(i,1,(n-id+1)/2) tt=tt*dis; c=a*tt; if ((n-id)%2) printf("%d\n",c.a[1][1]);else printf("%d\n",c.a[1][2]);*/ l=(n-id+1)/2; while (l){ sta.push(l%2); l/=2; } tt=one; while (!sta.empty()){ tt=tt*tt; if (sta.top()==1) tt=tt*dis; sta.pop(); } c=a*tt; if ((n-id)%2) printf("%d\n",c.a[1][1]);else printf("%d\n",c.a[1][2]); } }
相关文章推荐
- ZOJ 3780 Paint the Grid Again-贪心模拟/拓扑排序
- Win10预览版14316彩色主题下把标题栏改成白色的方法
- android studio 添加jar库和so文件
- C#学习笔记-WinForm
- 77. Combinations
- Constant buffers without constant pain(对于GPU constant buffer的说明).
- 数据库驱动程序URL
- sql server 2008表基本操作
- 集合特性
- JAVA读写配置properties配置文件
- 内存地址转换与分段
- -[LAGzipCompressor compressBytes:length:shouldFinish:] in libBPush.a(LAGzipCompressor.o)
- ios学习--NSUserDefaults 简介&使用 NSUserDefaults 存储自定义对象
- ionic 在Android运行,标题配置不居中问题
- 博客要求
- event.keyCode用法及列表
- DOS批处理
- PowerDesigner技巧
- PowerDesigner连接Oracle数据库建表序列号实现自动增长
- PowerDesigner生成的ORACLE 建表脚本中去掉对象的双引号,设置大、小写