【GDOI2016模拟3.9】暴走的图灵机
2016-04-13 20:43
323 查看
题目
分析
我们发现当两个字符串合并时,a0、a1表示左右两个字符串中有多少个T,C表示合并处新增的T的个数,那么a0=a1
a1=a0+a1+C
令s0和s1表示左右手两个字符串,那么每一次操作后左右手字符串分别为:
操作次数 左手 右手 0 s0 s1 1 s1 s0s1 2 s0s1 s1s0s1 3 s1s0s1 s0s1s1s0s1 4 s0s1s1s0s1 s1s0s1s0s1s1s0s1 5 s1s0s1s0s1s1s0s1 s0s1s1s0s1s1s0s1s0s1s1s0s1 ···
然后我们发现,从第1次操作以后,每次合并处是以s1s1和s1s0为一个循环。也就是说当|s0|>=m-1时,我们用KMP处理出a0、a1以及s1s1和s1s0合并时新增T的个数,然后O(N)递推一遍就可以了。
但是n<=10^9,只能拿60分。
因为递推时有循环,所以就可以构造矩阵,打个矩阵快速幂O(logN)。
#include <cmath> #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <queue> const long long maxlongint=2147483647; using namespace std; char s[30000],s1[30000],s2[30000],t[30000]; long long n,m,tot,ans,mo,next[30000],f[2][5],lens=1,lens1=1,nn,nnn; long long jz[5][5]= { {0,0,0,0,0}, {0,1,1,0,0}, {0,1,2,0,0}, {0,1,1,1,0}, {0,0,1,0,1} },b[5][5]; long long getnext() { long long i,j,k; j=0; for(i=2;i<=m;i++) { while(j>0 && t[j+1]!=t[i]) j=next[j]; if(t[j+1]==t[i]) j++; next[i]=j; } } long long kmp() { long long i,j,k; getnext(); j=0; for(i=1;i<=lens;i++) { while(j>0 && t[j+1]!=s[i]) j=next[j]; if(t[j+1]==s[i]) j++; if(j==m) f[0][1]++; } j=0; for(i=1;i<=lens1;i++) { while(j>0 && t[j+1]!=s1[i]) j=next[j]; if(t[j+1]==s1[i]) j++; if(j==m) f[0][2]++; } } long long kmp1() { long long i,j,k; k=0; for(i=lens-m+2;i<=lens;i++) s2[++k]=s[i]; for(i=1;i<=m-1;i++) s2[++k]=s1[i]; j=0; for(i=1;i<=m+m-2;i++) { while(j>0 && t[j+1]!=s2[i]) j=next[j]; if(t[j+1]==s2[i]) j++; if(j==m) f[0][0]++; } k=0; for(i=lens1-m+2;i<=lens1;i++) s2[++k]=s1[i]; for(i=1;i<=m-1;i++) s2[++k]=s[i]; j=0; for(i=1;i<=m+m-2;i++) { while(j>0 && t[j+1]!=s2[i]) j=next[j]; if(t[j+1]==s2[i]) j++; if(j==m) f[0][3]++; } k=0; for(i=lens1-m+2;i<=lens1;i++) s2[++k]=s1[i]; for(i=1;i<=m-1;i++) s2[++k]=s1[i]; j=0; for(i=1;i<=m+m-2;i++) { while(j>0 && t[j+1]!=s2[i]) j=next[j]; if(t[j+1]==s2[i]) j++; if(j==m) f[0][4]++; } } long long mi() { long long x=0,y=1,i,j,k; while(nn>0) { if(nn&1==1) { for(i=1;i<=4;i++) { f[x][i]=0; for(j=1;j<=4;j++) f[x][i]=(f[x][i]+(f[y][j]*jz[j][i])%mo)%mo; } x=y; y=1-y; } for(i=1;i<=4;i++) for(j=1;j<=4;j++) { b[i][j]=0; for(k=1;k<=4;k++) { b[i][j]=(b[i][j]+(jz[i][k]*jz[k][j])%mo)%mo; } } for(i=1;i<=4;i++) for(j=1;j<=4;j++) { jz[i][j]=b[i][j]; } nn/=2; } return y; } int main() { scanf("%d%d%d",&n,&m,&mo); scanf("%s",t+1); s[1]='0'; s1[1]='1'; long long i,j,k,l,x,y; for(j=1;j<=n;j++) { for(i=1;i<=lens1;i++) s2[i]=s1[i]; for(i=1;i<=lens;i++) s1[i]=s[i]; for(i=1;i<=lens1;i++) { s1[lens+i]=s2[i]; } for(i=1;i<=lens1;i++) s[i]=s2[i]; x=lens1; lens1+=lens; lens=x; y=j; if(lens>=m) break; } kmp(); if(n==y) { printf("%d\n",f[0][1]%mo); return 0; } kmp1(); f[1][1]=(f[0][2])%mo; f[1][2]=(f[0][1]+f[0][2]+f[0][0])%mo; f[1][3]=(f[0][3])%mo; f[1][4]=(f[0][4])%mo; n-=y+1; x=1; y=0; y=f[1][3]; n-=0; nnn=n%2; nn=n/2; x=mi(); if(nnn==1) { printf("%d\n",(f[x][2])%mo); return 0; } else printf("%d\n",f[x][1]%mo); }
相关文章推荐
- hibernate多对多关联
- 学生接外包需注意的地方
- HDU 4971 最大权闭合图
- WCF学习问题分享1
- 2013山东省第四届ACM省赛 Alice and Bob
- java中用中国网建提供的SMS短信平台发送短信
- 操作系统2015(四川大学软件学院)
- Android自定义View的一些理解
- 【Oracle】5.事务
- 0基础学C#教程2--------C#如何调用excel,试用最新版的excel
- 局部加权线性回归
- 个人加快android studio编译速度(不改),加个ssd就不用看了- -
- Systrace快捷命令
- 似魔鬼的 『 document.write 』
- Dubbo超时和重连机制
- 用 Nokitjs 解决前端开发中的跨域问题
- 冒泡排序
- FindBugs插件的安装与使用
- javanio 实现socket通信
- 制作网页---BJUI订制控件