535D Tavas and Malekas

题目大意

给你一个串和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\n",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\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/yzxverygood/p/11441384.html