HDU 6153 A Secret

A Secret

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 256000/256000 K (Java/Others)

Problem Description

Today is the birthday of SF,so VS gives two strings S1,S2 to SF as a present,which have a big secret.SF is interested in this secret and ask VS how to get it.There are the things that VS tell:
Suffix(S2,i) = S2[i…len].Ni is the times that Suffix(S2,i) occurs in S1 and Li is the length of Suffix(S2,i).Then the secret is the sum of the product of Ni and Li.
Now SF wants you to help him find the secret.The answer may be very large, so the answer should mod 1000000007.

Input

Input contains multiple cases.
The first line contains an integer T,the number of cases.Then following T cases.
Each test case contains two lines.The first line contains a string S1.The second line contains a string S2.
1<=T<=10.1<=|S1|,|S2|<=1e6.S1 and S2 only consist of lowercase ,uppercase letter.

Output

For each test case,output a single line containing a integer,the answer of test case.
The answer may be very large, so the answer should mod 1e9+7.

Sample Input

2
aaaaa
aa
abababab
aba

Sample Output

13
19
Hint
case 2:
Suffix(S2,1) = “aba”,
Suffix(S2,2) = “ba”,
Suffix(S2,3) = “a”.
N1 = 3,
N2 = 3,
N3 = 4.
L1 = 3,
L2 = 2,
L3 = 1.
ans = (33+32+4*1)%1000000007.

题意:

给你两个字符串(需要反转),第一个是文本串,第二个模式串,要求你求出模式串的所有从0开始的连续字串在文本串中出现的次数*字串个数。

思路:

首先将两个反转,因为题目要求的是后缀,kmp算法求出来的是前缀,所以先反转。
然后kmp中求出next数组用于计算kmp算法。
如果暴力的话,那就是求出每一个的字串,然后求出多少个在一次相加,但是TLE了。所以就要用其他的方法了,注意到每一个的字串中,假如ab满足条件是前缀,那么a肯定也会满足条件,所以这个时候只要把最后的那个位数的值++就行了,然后算前缀和,就是从末尾开始遍历因为后面的肯定包括了前面的了。

#include 
#include 
#include 
#include 
using namespace std;
typedef long long ll;
const int maxn = 1e+6 + 10;
const int mod = 1e+9 + 7;
char mo[maxn], str[maxn];
int Next[maxn];
ll ans[maxn];
void GetNext() {
    int len = strlen(mo), j = -1, i = 0;
    Next[0] = -1;
    while (i < len) {
        if (j == -1 || mo[i] == mo[j]) Next[++i] = ++j;
        else j = Next[j];
    }
}
void kmp() {
    memset(ans, 0, sizeof(ans));
    int len1 = strlen(str), len2 = strlen(mo), k = 0, j = 0;
    ll sum = 0;
    str[len1] = ' ';
    while (k < len1 + 1) {
        if (j == -1 || str[k] == mo[j]) {
            k++;
            j++;
        } else {
            ans[j]++;
            j = Next[j];
        }
        if (j == len2) {
            ans[j]++;
            j = Next[j];
        }
    }
    for (int i = len2; i >= 0; i--) {
        ans[i] = (ans[i] + ans[i + 1]) % mod;
        sum = (sum + (ans[i] * i) % mod) % mod;
    }
    printf("%lld\n", sum);
}
int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        scanf("%s%s", str, mo);
        strrev(str);
        strrev(mo);
        GetNext();
        kmp();
    }
    return 0;
}

你可能感兴趣的:(HDU)