zoukankan      html  css  js  c++  java
  • HDU 6068 Classic Quotation KMP+DP

    Classic Quotation

    Problem Description
    When online chatting, we can save what somebody said to form his ''Classic Quotation''. Little Q does this, too. What's more? He even changes the original words. Formally, we can assume what somebody said as a string S whose length is n. He will choose a continuous substring of S(or choose nothing), and remove it, then merge the remain parts into a complete one without changing order, marked as S. For example, he might remove ''not'' from the string ''I am not SB.'', so that the new string S will be ''I am SB.'', which makes it funnier.



    After doing lots of such things, Little Q finds out that string T occurs as a continuous substring of S very often.

    Now given strings S and T, Little Q has k questions. Each question is, given L and R, Little Q will remove a substring so that the remain parts are S[1..i] and S[j..n], what is the expected times that T occurs as a continuous substring of S if he choose every possible pair of (i,j)(1iL,Rjn) equiprobably? Your task is to find the answer E, and report E×L×(nR+1) to him.

    Note : When counting occurrences, T can overlap with each other.
     
    Input
    The first line of the input contains an integer C(1C15), denoting the number of test cases.

    In each test case, there are 3 integers n,m,k(1n50000,1m100,1k50000) in the first line, denoting the length of S, the length of T and the number of questions.

    In the next line, there is a string S consists of n lower-case English letters.

    Then in the next line, there is a string T consists of m lower-case English letters.

    In the following k lines, there are 2 integers L,R(1L<Rn) in each line, denoting a question.
     
    Output
    For each question, print a single line containing an integer, denoting the answer.
     
    Sample Input
    1 8 5 4 iamnotsb iamsb 4 7 3 7 3 8 2 7
     
    Sample Output
    1 1 0 0
     

    题意:

      给两个字符串只包含小写字母,长度分别为n,m

      k个询问,每次询问给出一个L,R

      任意的 ( ≤ ≤ ≤ ≤ ) 删除S串范围(i+1,j-1)内的字符,求出T串在新串内出现的次数总和

    题解:

      我还是照搬官方题解吧

      

    #include<bits/stdc++.h>
    using namespace std;
    #pragma comment(linker, "/STACK:102400000,102400000")
    #define ls i<<1
    #define rs ls | 1
    #define mid ((ll+rr)>>1)
    #define pii pair<int,int>
    #define MP make_pair
    typedef long long LL;
    typedef unsigned long long ULL;
    const long long INF = 1e18+1LL;
    const double pi = acos(-1.0);
    const int N = 6e4+10, M = 2e2+20,inf = 2e9;
    
    int zfail[N],ffail[N];
    LL dp[N][M],f[N][M],sumdp[N][M],sumf[N][M],dp2[N][M],f2[N][M];
    char a[N],b[N];
    int n,m,k,T;
    LL solve(int ll,int rr) {
        LL ret = 0;
        ret += 1LL * sumdp[ll][m] * (n - rr + 1) + 1LL * sumf[rr][1] * (ll);
        for(int i = 1; i < m; ++i) {
            ret += 1LL*dp2[ll][i] * f2[rr][i+1];
        }
        return ret;
    }
    void init() {
        for(int j = 0; j <= m+1; ++j) zfail[j] = 0,ffail[j] = m+1;
        for(int i = 0; i <= n+1; ++i)
            for(int j = 0; j <= m+1; ++j)
                dp[i][j] = 0,f[i][j] = 0,sumdp[i][j] = 0,sumf[i][j] = 0;
        int j = 0;
        for(int i = 2; i <= m; ++i) {
            while(j&&b[j+1]!=b[i]) j = zfail[j];
            if(b[j+1] == b[i]) j++;
            zfail[i] = j;
        }
        j = m+1;
        for(int i = m-1; i >= 1; --i) {
            while(j<=m&&b[j-1]!=b[i]) j = ffail[j];
            if(b[j-1] == b[i]) j--;
            ffail[i] = j;
        }
        j = 0;
        for(int i = 1; i <= n; ++i) {
            while(j&&a[i]!=b[j+1]) j = zfail[j];
            if(b[j+1] == a[i]) j++;
            dp[i][j] += 1;
        }
        j = m+1;
        for(int i = n; i >= 1; --i) {
            while(j<=m&&b[j-1]!=a[i]) j = ffail[j];
            if(b[j-1] == a[i]) j--;
            f[i][j] += 1;
        }
    
        for(int i = 1; i <= n; ++i) {
            for(int j = 1; j <= m; ++j) {
                dp[i][j] += dp[i-1][j];
                sumdp[i][j] += sumdp[i-1][j]+dp[i][j];
            }
        }
        for(int i = n; i >= 1; --i) {
            for(int j = m; j >= 1; --j) {
                f[i][j] += f[i+1][j];
                sumf[i][j] += sumf[i+1][j]+f[i][j];
            }
        }
    }
    
    void init2() {
         for(int i = 0; i <= n+1; ++i)
            for(int j = 0; j <= m+1; ++j)
                dp2[i][j] = 0,f2[i][j] = 0;
        for(int i = 0; i <= n+1; ++i)
            dp2[i][0] = 1,f2[i][m+1] = 1;
    
    
        for(int i = 1; i <= n; ++i) {
            for(int j = 1; j <= m; ++j) {
                if(a[i] == b[j] && dp2[i-1][j-1])
                    dp2[i][j] = 1;
            }
        }
         for(int i = 1; i <= n; ++i) {
            for(int j = 1; j <= m; ++j) {
                    dp2[i][j] += dp2[i-1][j];
            }
        }
        for(int i = n; i >= 1; --i) {
            for(int j = m; j >= 1; --j) {
                if(a[i] == b[j] && f2[i+1][j+1])
                    f2[i][j] = 1;
            }
        }
          for(int i = n; i >= 1; --i) {
            for(int j = m; j >= 1; --j) {
              f2[i][j] += f2[i+1][j];
            }
        }
    }
    
    int main() {
        scanf("%d",&T);
        while(T--) {
            scanf("%d%d%d%s%s",&n,&m,&k,a+1,b+1);
            init();
            init2();
            while(k--) {
                int L,R;
                scanf("%d%d",&L,&R);
                printf("%lld
    ",solve(L,R));
            }
        }
        return 0;
    }
  • 相关阅读:
    Git------解决右键不显示Git Bash Here问题
    AngularJS------Error: Cannot find module '@angular-devkit/core'
    AngularJS------命令行
    AngularJS------报错"The selector "app-user-item" did not match any elements"
    AngularJS------使用VSCode创建的Angular项目部署IIS
    JQuery------各种版本下载
    docker 卸载
    oauth2.0授权协议
    web service 简介
    Python 优雅获取本机 IP 方法
  • 原文地址:https://www.cnblogs.com/zxhl/p/7293968.html
Copyright © 2011-2022 走看看