题目大意
给你一个串和m个下标
问你一个长度为n的串每一个下标开始的后缀的前缀都包含给定的串的方案数
分析
对于给定的串求出z数组
对于两个串不重叠的情况就是中间都不包含的数随便填即可
对于重叠的情况判断相交部分的左端点的z[i]是否大于等于重叠长度即可
代码
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<cctype> #include<cmath> #include<cstdlib> #include<queue> #include<ctime> #include<vector> #include<set> #include<map> #include<stack> using namespace std; const int mod = 1e9+7; int n,m,q,z[1000100],ans,wh[1000100],pw[1000100]; char s[1000100]; inline void get_z(){ int i,j,k,l=0,r=0; z[0]=n; for(i=1;i<n;i++){ if(i<=r)z[i]=min(r-i+1,z[i-l]); while(i+z[i]<n&&s[z[i]]==s[z[i]+i])z[i]++; if(i+z[i]-1>r)r=i+z[i]-1,l=i; } } int main(){ int i,j,k; scanf("%d%d",&m,&q); scanf("%s",s); n=strlen(s); get_z(); pw[0]=1; for(i=1;i<=1000000;i++)pw[i]=1ll*pw[i-1]*26%mod; for(i=1;i<=q;i++)scanf("%d",&wh[i]); if(!q){ printf("%d ",pw[m]); return 0; } ans=pw[wh[1]-1]; int la=wh[1]+n-1; for(i=2;i<=q;i++){ if(wh[i]>la)ans=1ll*ans*pw[wh[i]-la-1]%mod; else { if(z[n-la+wh[i]-1]<la-wh[i]+1){ puts("0"); return 0; } } la=wh[i]+n-1; if(la>m){ puts("0"); return 0; } } if(m>la)ans=1ll*ans*pw[m-la]%mod; printf("%d ",ans); return 0; }