CF494B - Obsessive String(dp+kmp)

题目

Description

题解

dp苦手表示不会做qwq
看题解看老半天才理解。关键就是有次序条理地计数。

\(a_i\)为包含以位置i为结尾的区间的所有取法。
用kmp找出所有子串t在母串结尾的位置,称这样的位置为好位置。

显然,区间[l,r]的所有方案即为\(\sum_{i=l}^{r}{a_i}\)。所以关键是求\(a_i\)

  • 如果位置i不是好位置,那么\(a_i=a_{i-1}\),因为为了包含子串,它只能从\(a_{i-1}\)扩展。
  • 如果位置i是好位置,那么从i开始,只取一个区间包含当前位置的子串,有i-|t|+1总方案;或者把区间分成[1, j]和[j+1, i],这样的方案数为\(\sum_{i=1}^{j}{a_i}\),又由于不能重叠,j的范围为[1, i-|t|]。这样总方案数为\(\sum_{j=1}^{i-|t|}{\sum_{k=1}^{j}{a_k}}+i-|t|+1\)

所以维护一个前缀和的前缀和即可。

#include <bits/stdc++.h>
 
#define endl '\n'
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define FILE freopen(".//data_generator//in.txt","r",stdin),freopen("res.txt","w",stdout)
#define FI freopen(".//data_generator//in.txt","r",stdin)
#define FO freopen("res.txt","w",stdout)
#define pb push_back
#define mp make_pair
#define seteps(N) fixed << setprecision(N) 
typedef long long ll;
 
using namespace std;
/*-----------------------------------------------------------------*/
 
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
#define INF 0x3f3f3f3f
 
const int N = 3e5 + 10;
const int M = 1e9 + 7;
const double eps = 1e-5;
 
char s[N];
char t[N];
int nt[N];
bool flag[N];
 
void getnext() {
    int i = 0, j = -1;
    nt[i] = j;
    while(t[i]) {
        if(j == -1 || t[i] == t[j]) {
            i++, j++;
            nt[i] = j;
        } else {
            j = nt[j];
        }
    }
}
 
void work() {
    int i = 0, j = 0;
    while(s[i]) {
        if(j == -1 || s[i] == t[j]) {
            i++, j++;
            if(!t[j]) {
                flag[i - 1] = 1;
                j = nt[j];
            }
        } else {
            j = nt[j];
        }
    }
}
 
int sum1[N];
int sum2[N];
int dp[N];
 
int main() {
    IOS;
    cin >> s >> t;
    int n = strlen(t);
    getnext();
    work();
    for(int i = 0; s[i]; i++) {
        if(flag[i]) {
            dp[i] = (i - n >= 0 ? sum2[i - n] : 0) + i - n + 2; 
            dp[i] %= M;
        } else {
            if(i > 0) {
                dp[i] = dp[i - 1];
            } else dp[i] = 0;
        }
        if(i > 0) {
            sum1[i] += sum1[i - 1] + dp[i];
            sum1[i] %= M;
            sum2[i] += sum2[i - 1] + sum1[i];
            sum2[i] %= M;
        } else sum1[i] = sum2[i] = dp[i];
    }
    int ans = 0;
    for(int i = 0; s[i]; i++) {
        ans += dp[i];
        ans %= M;
    }
    cout << ans << endl;
}
posted @ 2020-08-14 15:43  limil  阅读(126)  评论(0编辑  收藏  举报