这题题意真的是玄学==读了半年

题目在这里

题意:给两个串s,t,0<|s|,|t|<=1e5,现在要把s分割成不重合的k段,每段的起点是a[i],终点是b[i].也就是串s[a[i]]s[a[i]+1]s[a[i]+2].....s[b[i]]这一段。要求每段都有一个子串是t。求有多少种分割的方案
思路:首先不难想到这样暴力:dp[i]表示把i作为最后一段子串终止点的方案数dp[i] = dp[j] *(si - j) + dp[j + 1] * (si - j - 1).....+dp[si-1]*(1)
si是最后一段子串想要包含t的最后面的开始点。然后观察等式右边发现这个公式可以维护一个前缀答案和tmp和前缀和sum,然后si每向右边移动一位。sum就加上dp[si],tmp就加上sum;
每个点的si可以用KMP来求==具体见代码:

代码:

 

 #include<bits/stdc++.h>
 using namespace std;
 typedef long long ll;
 const int maxn = 1e5 + 10;
 const ll mod = 1e9 + 7;
 char s[maxn] , t[maxn];
 int nxt[maxn];
 bool mat[maxn];
 ll dp[maxn];
 int lastmat[maxn];
 void get_next(){
     int lent = strlen(t + 1)+1;
     nxt[0] = 0;
     nxt[1] = 0;
     int i = 2 , j = 0;
     while(i <= lent){
        if(j != 0 && t[i - 1] != t[j]) j = nxt[j];
        else nxt[i++] = ++j;
     }
     for(int i = 1; i <= lent;i++){
        int xt = nxt[i];
        while(t[i] == t[xt]&&xt != 0) nxt[i] = nxt[xt] ,xt = nxt[xt];
     }
}
 void KMP(){
   memset(mat,0,sizeof(mat));
   int lent = strlen(t + 1) + 1;
   int lens = strlen(s + 1);
   int j = 1;
   for(int i = 1; i <= lens;i++){
        while(j != 0 && s[i] != t[j]) j = nxt[j];
        j++;
        if(j == lent) mat[i] = 1 , j = nxt[j];
   }
}
void init(){
    int si = 0;
    int lens = strlen(s + 1);
    int lent = strlen(t + 1);
    for(int i = 1 ; i <= lens;i++){
         if(mat[i]){
            si = i - lent + 1;
         }
         lastmat[i] = si;
    }
}
 int main()
 {
     while(~scanf("%s%s",s+1,t+1)){
        get_next();
        KMP();
        init();
        memset(dp,0,sizeof(dp));
        dp[0] = 1;
        ll sum = 0;
        ll tmp = 0;
        int lens = strlen(s + 1);
        ll ans = 0;
        int si = 0;
        for(int i = 1; i <= lens;i++){
            while(si < lastmat[i]){
                sum += dp[si++];
                if(sum >= mod) sum -= mod;
                tmp += sum;
                if(tmp >= mod) tmp -= mod;
            }
            dp[i] = tmp;
            ans += tmp;
            if(ans >= mod) ans -= mod;
        }
        printf("%I64d\n",ans);
     }
 }
View Code