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)(1≤i≤L,R≤j≤n) equiprobably? Your task is to find the answer E, and report E×L×(n−R+1) to him.

Note : When counting occurrences, T can overlap with each other.

Input

The first line of the input contains an integer C(1≤C≤15), denoting the number of test cases.

In each test case, there are 3 integers n,m,k(1≤n≤50000,1≤m≤100,1≤k≤50000) 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(1≤L<R≤n) 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

  任意的 ( i , j ) ( 1 ≤ i ≤ L , R ≤ j ≤ n ) 删除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\n",solve(L,R));
        }
    }
    return 0;
}
时间: 2024-10-13 12:02:05

HDU 6068 Classic Quotation KMP+DP的相关文章

hdu 6068 Classic Quotation(字符串hash)

题目链接:hdu 6068 Classic Quotation 题意: 给你两个字符串S和T,现在有q个询问,每个询问给出一个l,r,问S[1..i] 和 S[j..n](1≤i≤L,R≤j≤n)中有多少个T,求出全部的总和. 题解: Claris的官方题解: 这里我用hash代替了kmp的作用. 1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=(a);i<=(b);++i) 3 using namespace std; 4

hdu 6068--Classic Quotation(kmp+DP)

题目链接 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

[kmp+dp] hdu 4628 Pieces

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4622 Reincarnation Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others) Total Submission(s): 2096    Accepted Submission(s): 715 Problem Description Now you are back,and

[HDOJ5763]Another Meaning(KMP, DP)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5763 题意:给定两个字符串a和b,其中a中的字符串如果含有子串b,那么那部分可以被替换成*.问有多少种替换方法. kmp求出b在a中完全匹配后的结尾位置,然后dp(i)表示匹配到i时替换的方案数(不替换也算一次方案).首先更新dp(i)=dp(i-1),当且仅当i点是一个完全匹配的终点时,加上dp(i-nb)处的值. 1 #include <bits/stdc++.h> 2 using names

HDU Count the string (KMP)

题面见http://acm.hdu.edu.cn/showproblem.php?pid=3336 给你一个字符串,让你找它的前缀在整个字符串出现的次数. 作为一个不会思考的笨比,直接用kmp去一个个计数,果不其然,t了 找了博客来看,大概就是kmp+dp,要用到kmp中的pret数组(有的人习惯叫next数组,知道就行) dp的方程形式很简单,但很难理解. 这是原博主的原话: 如果用dp[i]表示该字符串前i个字符中出现任意以第i个字符结尾的前缀的次数,它的递推式是 dp[i]=dp[pret

hdu 3746 Cyclic Nacklace (KMP求最小循环节)

//len-next[len]为最小循环节的长度 # include <stdio.h> # include <algorithm> # include <string.h> using namespace std; int len; char a[100010]; int next[100010]; void Getnext() { int i=0,j=-1; next[0]=-1; while(i<=len) { if(j==-1||a[i]==a[j]) i

hdu 3555 Bomb(数位dp)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3555 题目大意:就是给你一个数n,判断从0到n有多少个数含有数字49...... 是不是觉得跟hdu2089很相似呀... 思路:跟hdu2089一样的,注意给出的数比较大,所以这儿用__int64  .... code: #include<cstdio> #include<iostream> #include<cstring> #include<algorithm&

HDU 1231 最大连续子序列 DP题解

典型的DP题目,增加一个额外要求,输出子序列的开始和结尾的数值. 增加一个记录方法,nothing special. 记录最终ans的时候,同时记录开始和结尾下标: 更新当前最大值sum的时候,更新开始节点. const int MAX_N = 10001; long long arr[MAX_N]; int N, sta, end; long long getMaxSubs() { long long sum = 0, ans = LLONG_MIN; int ts = 0; for (int

[ACM] hdu 2089 不要62(数位Dp)

不要62 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 19043    Accepted Submission(s): 6442 Problem Description 杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer). 杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就