网络赛,HDU6153《KMP》

来源:互联网 发布:淘宝嘉年华英伦休闲鞋 编辑:程序博客网 时间:2024/06/11 05:06

网络赛,HDU6153


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 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 = (3*3+3*2+4*1)%1000000007.

题意:给一个匹配串和一个模式串,用模式串的后缀串去和匹配串匹配,答案加等于后缀的长度乘匹配的个数。
这题如果真要求后缀然后一个个匹配应该会超时,比赛时也想过用ac自动机,但是发现ac自动机还不如把字符串倒置再用kmp快,首先,把两个字符串都倒置,求出模式从的next数组,再用一个数组存while(i>0) sum+=i,i=next[i]的值,如样例aba,如果aba能匹配,那么a肯定也能匹配。代码如下:

#include <vector>#include <list>#include <map>#include <set>#include <deque>#include <queue>#include <stack>#include <bitset>#include <algorithm>#include <functional>#include <numeric>#include <utility>#include <complex>#include <sstream>#include <iostream>#include <iomanip>#include <cstdio>#include <cmath>#include <cstdlib>#include <cstring>#include <ctime>#include <cassert>using namespace std;typedef long long ll;const int MOD = 1e9 + 7;const int MAXN = 1e6 + 10;char t[MAXN], p[MAXN];int nextt[MAXN],nex[MAXN];ll sum;void getnext(){    int m = strlen(p);    nextt[0] = -1;//长度为0时没有意义    int i = 0,j = -1;//i为即将比较的后缀下标, j为即将比较的前缀下标    while(i < m)//保证模式串下标不超长度    {        while(j >= 0 && p[i] != p[j])//若因为j = -1, 则无串可配,若因为失配, 则前缀下标前移        {            j = nextt[j];        }        //直到匹配到了, 两个下标就同时前移        i++; j++;        nextt[i] = j;        nex[i]=(nex[j]+i)%MOD;  //记录对于匹配到该位置的子串的和    }}void kmp(){    getnext();    int n = strlen(t);    int m = strlen(p);    int i = 0, j = 0;//前者大串的下标, 后者模式串下标    while(i < n)    {        while(j >= 0 && t[i] != p[j])        {            j=nextt[j];        }        i++; j++;        //cout << i << " " << j << endl;        sum=(sum+nex[j])%MOD;        if(j == m)        {            j = nextt[j];        }    }}int main(){    ios::sync_with_stdio(false);    cin.tie(0);    int T; cin >> T;    memset(nex,0,sizeof(nex));    while(T--)    {        cin >> t >> p;        strrev(t); strrev(p);//倒置字符串        sum = 0;        kmp();        cout << sum << endl;    }    return 0;}
原创粉丝点击