标签:
传送门在这里
题意:给出一个字符串的一个子串,告诉你子串在某些位置和原串匹配,求一共有多少可能的原串
思路:其实就是要判断给出子串的所有前缀和后缀哪些是相等的。
首先kmp的next数组求的是所有前缀子串(a1 a1a2 a1a2a3...)中长度最大的前缀和后缀的长度,
设字符串长度为len,那么next[len]得到的是整个字符串中长度最长的相等的前缀和后缀,并且可知,所有起始位置小于next[len]的后缀都不可能存在相等的前缀了,那么下一步就是求起始位置在[next[len]+1,len]中的所有相等后缀。
假设长度第二的相等后缀位置为pos,显然有a[1]a[2]..a[k]=a[pos]a[pos+1]..a[pos+k-1],这里pos+k-1==len并且k<next[len],我们要求的k其实就是a[1]a[2]...a[next[len]]这个前缀子串中最长的相等前缀的和后缀,即k=nextnext[len]].于是我们可以找出所有相等的前缀和后缀的位置。
代码:
#include<iostream> #include<string.h> #include<stdio.h> #include<map> #include<set> using namespace std; #define Mod 1000000007 char s[1000005]; int a[1000005]; int len; int next[1000005]; int v[1000005]; void getnext(char* s){ next[0]=next[1]=0; for(int i=1;i<len;i++){ int j=next[i]; while(j&&s[i]!=s[j]) j=next[j]; if(s[i]==s[j]) next[i+1]=j+1; else next[i+1]=0; } } int main(){ int i,j; int n,m; scanf("%d%d",&n,&m); scanf("%s",s); for(i=1;i<=m;i++){ scanf("%d",&a[i]); } len=strlen(s); if(m==0){ long long ans=1; for(i=1;i<=n;i++){ ans=ans*26%Mod; } cout<<ans<<endl; return 0; } getnext(s); for(i=len;next[i];i=next[i]){ v[len-next[i]]=1; } long long ans=1; for(i=1;i<a[1];i++){ ans=ans*26%Mod; } for(i=2;i<=m;i++){ if(a[i-1]+len<=a[i]){ for(j=a[i-1]+len;j<a[i];j++){ ans=ans*26%Mod; } } else{ int pos=a[i]-a[i-1]; if(!v[pos]){ ans=0; break; } } } for(i=a[m]+len;i<=n;i++){ ans=ans*26%Mod; } cout<<ans<<endl; return 0; }
标签:
原文地址:http://blog.csdn.net/u011822304/article/details/45694497