题目:http://codeforces.com/contest/535/problem/D
题意:给定文本串T的长度为L和模式串P在文本串T的首位置的个数n,再给出模式串P,然后给出n个数,代表模式串P在文本串T的首位置。求文本的可能情况,结果模上109 + 7。
分析:这题主要是判断模式串P填在文本串T里面是否合法,如果不合法,那么答案就是0,如果合法就看文本串T里面有多少个位置没有填,记为x,那么结果就是26^x。直接往文本串里面填模式串的话会超时。判断是否合法,其实就是往文本串T里面填模式串P判断两个模式串的重叠部分是否匹配,即判断模式串的前缀和后缀是否匹配,这就要用到KMP算法。首先求出next数组(next数组不能优化),利用next数组将可重叠的长度全部存进查询表,往文本串T里面填模式串P的时候求出模式串的重叠长度,然后再查询表里面找长度是否存在,若不存在就不合法,若存在就继续....
代码:
/* ID: 15507481 PROG: test LANG: C++11 */ #include <iostream> #include <fstream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> #include <set> #include <map> #include <vector> #include <string> #include <sstream> #include <queue> #include <stack> #include <deque> using namespace std; typedef long long LL; #define MAXN 2000000 #define MOD 1000000007ll char sub[MAXN]; int pos[MAXN]; int Next[MAXN]; bool match[MAXN]; void getnext(int Next[],char str[]); LL my_pow(int n) { LL ret=1ll,a=26ll; while(n) { if(n&1) ret=ret*a%MOD; n>>=1; a=a*a%MOD; } return ret%MOD; } int main() { int N,num,i,j,k; scanf("%d%d",&N,&num); scanf("%s",sub); int len=strlen(sub); sub[len]='&'; sub[len+1]='\0'; len++; for(i=0;i<num;i++) scanf("%d",&pos[i]); getnext(Next,sub); int pos1=len-1; while(Next[pos1]!=-1) { match[Next[pos1]]=true; pos1=Next[pos1]; } int ans=0; bool tag=true; for(i=1;i<num;i++) { if(pos[i-1]+len-2<pos[i]) { ans+=pos[i]-(pos[i-1]+len-2)-1; } else { if(!match[pos[i-1]+len-2-pos[i]+1]) { tag=false; break; } } } if(num==0) ans=N; else { ans+=N-(pos[num-1]+len-2); ans+=pos[0]-1; } if(tag) cout<<my_pow(ans)<<'\n'; else printf("0\n"); return 0; } void getnext(int Next[],char str[]) { int len=strlen(str); Next[0]=-1; int k=-1; int j=0; while(j<len) { if(k==-1 ||str[j]==str[k]) { j++; ++k; Next[j]=k; } else k=Next[k]; } } /* * * * * * * */