zoukankan      html  css  js  c++  java
  • CF494B

    题目

    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 '
    '
    #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;
    }
    
  • 相关阅读:
    P2207 Photo
    P1022 计算器的改良
    P1003 铺地毯
    P3014 [USACO11FEB]牛线Cow Line && 康托展开
    P4180 【模板】严格次小生成树[BJWC2010]
    P2776 [SDOI2007]小组队列
    P2426 删数
    P1948 [USACO08JAN]电话线Telephone Lines
    P1978 集合
    P1564 膜拜
  • 原文地址:https://www.cnblogs.com/limil/p/13502631.html
Copyright © 2011-2022 走看看