hdoj 6153 A Secret

来源:互联网 发布:head first java电子书 编辑:程序博客网 时间:2024/06/05 03:53

题目链接:A Secret

题目大意:给你两个字符串,然后需要你对模式串的后缀去对原串匹配,原串后缀长度为1的出现多少次贡献就是1*n,长度为2的贡献就是2*n,然后要求你算出这个总贡献mod(1e9+7)

题目思路:既然要求的是后缀匹配,那么我们将两个串都翻转过来进行正着匹配就好了,然后我们需要去在KMP里面去算,当KMP匹配到失配的时候那么我们可以知道这时的j就是我们已经匹配成功的串,那么这个串的贡献是多少呢?自然是j*(j+1)/2,因为匹配了j个字符,那么j-1、j-2、…、1个字符肯定都在这之前已经匹配到了,还需要注意的一个问题是,最后失配的情况,可能一直到最后都不会失配,所以我们让其失配,然后就做一下处理就好了,这题因为j*(j+1)/2是整数,所以不需要用逆元去算,直接暴力去算就好了

#include <map>#include <set>#include <queue>#include <stack>#include <cmath>#include <vector>#include <cstdio>#include <cstring>#include <cstdlib>#include <iostream>#include <algorithm>using namespace std;typedef long long ll;const int maxn = 1e6+10;const int mod = 1e9+7;ll n,Next[maxn],ret;char mo[maxn],str[maxn],ans[maxn];void getNext(){    ll i = 0,j = -1,len = strlen(mo);    while(i < len){        if(j == -1||mo[i] == mo[j]) Next[++i] = ++j;        else j = Next[j];    }}void kmp(){    ll i = 0,j = 0,len1 = strlen(mo),len2 = strlen(str);    ll ans = 0;    while(i < len2){        if(j == -1||mo[j] == str[i]){            j++;            i++;        }        else ret = (ret+((j+1)*j)/2)%mod,j = Next[j];    }    while(j != -1){        ret = (ret+((j+1)*j)/2)%mod;        j = Next[j];    }    printf("%lld\n",ret);}int main(){    int t;    scanf("%d",&t);    while(t--){        ret = 0ll;        scanf("%s%s",str,mo);        reverse(str,str+strlen(str));        reverse(mo,mo+strlen(mo));        memset(Next,-1,sizeof(Next));        getNext();        kmp();    }    return 0;}

Uupdate:这个KMP写法有问题,有一组数据str:baabaa
mo:caabaa过不去,所以需要使用正确的姿势:

#include <bits/stdc++.h>using namespace std;const int N = 1000005;const int Q = 1e9 + 7;char s[N] , t[N];int n , m , f[N] , cnt[N];void work() {    scanf("%s%s" , t , s);    n = strlen(t);    m = strlen(s);    reverse(s , s + m);    reverse(t , t + n);    f[0] = f[1] = 0;    for (int i = 1 ; i < m ; ++ i) {        int j = f[i];        while (j && s[i] != s[j])            j = f[j];        f[i + 1] = s[i] == s[j] ? j + 1 : 0;    }    memset(cnt , 0 , sizeof(int) * (m + 1));    for (int i = 0 , j = 0 ; i < n ; ++ i) {        while (j && t[i] != s[j])            j = f[j];        j += (t[i] == s[j]);        ++ cnt[j];    }    for (int i = m ; i > 0 ; -- i) {        cnt[f[i]] += cnt[i];    }    int res = 0;    for (int i = 1 ; i <= m ; ++ i) {        res += (long long)cnt[i] * i % Q;        res %= Q;    }    cout << res << endl;}int main() {    int T;    scanf("%d" , &T);    while (T --) {        work();    }}
原创粉丝点击