hdu6153 A Secret CCPC网络赛 51nod 1277 KMP

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=6153

题意:

给出两个字符串S1,S2,求S2的所有后缀在S1中出现的次数与其长度的乘积之和。

思路:

CCPC网络赛题解: https://post.icpc-camp.org/d/714-ccpc-2017

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1277   是一样的

将s1,s2翻转,转化为求前缀在s1中出现的次数

next数组,记t[i]为长度为i的前缀出现的次数,显然t[n]=1。next[i]即为子串[0,i]的后缀与前缀重复的最长长度,因此可以统计一下next[i]的取值的个数,然后较长的前缀出现一次代表较短的前缀也一次,递推一下即可,复杂度为O(n)。

就是说统计所有在模式串中能匹配上的位置匹配了多少次,再通过fail指针逆推回去,因为长的前缀匹配上了,所有短的前缀也能匹配那么多次。

http://blog.csdn.net/algzjh/article/details/77415529  将S1,S2倒转,用KMP求得S2fail数组,在S1上滑动的同时,累加结果。 这种是不对的

hack:

 

KMP好难啊!!! dalao的模板题,我没做出来 菜的一笔

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define MS(a) memset(a,0,sizeof(a))
#define MP make_pair
#define PB push_back
const int INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3fLL;
inline ll read(){
    ll x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
//////////////////////////////////////////////////////////////////////////
const int maxn = 1e6+10;
const int mod = 1e9+7;

char s[maxn],t[maxn];
int l1,l2,f[maxn];
ll ans,cnt[maxn];

void getfail(){
    f[0] = f[1] = 0;
    for(int i=1; i<l2; i++){
        int j = f[i];
        while(j && s[i]!=s[j]) j=f[j];
        f[i+1] = (s[i]==s[j]) ? j+1 : 0;
    }
}

int main(){
    int T = read();
    while(T--){
        scanf("%s%s",t,s);
        l1 = strlen(t), l2 = strlen(s);
        reverse(t,t+l1);
        reverse(s,s+l2);
        getfail();
        MS(cnt);
        int j=0;
        for(int i=0; i<l1; i++){
            while(j && t[i]!=s[j]) j=f[j];
            if(t[i] == s[j]) j++;
            ++cnt[j];
        }

        for(int i=l2; i>=0; i--){
            cnt[f[i]] += cnt[i];
            cnt[f[i]] %= mod;
        }
        ll ans = 0;
        for(int i=0; i<=l2; i++){
            ans = (ans+cnt[i]*i)%mod;
        }
        cout << ans << endl;
    }
}

 

错误代码[数据弱,可以AC]:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 10;
const int mod = 1e9 + 7;
char str[maxn],tt[maxn];
int nxt[maxn];
ll ans = 0;

void getnext(char *t)
{
    int len = strlen(t);
    nxt[0] = nxt[1] = 0;
    for (int i = 1; i < len; i++)
    {
        int j = nxt[i];
        while (j > 0 && t[i] != t[j]) j = nxt[j];
        nxt[i+1] = (t[i]==t[j]) ? j+1 : 0;
    }
}

void kmp(char *s, char *t)
{
    ll j = 0;
    ans = 0;
    int ll = strlen(s);
    int len = strlen(t);
    for (int i=0; i<ll; i++) {
        while (j > 0 && s[i] != t[j]) { ans+=((j*(j+1))/2)%mod; j=nxt[j];}
        if(s[i] == t[j]) j++;
        if(j == len) { ans+=((j*(j+1))/2)%mod; j = nxt[j];}
        if (ans >= mod)
            ans -= mod;
    }
    while(j >= 1){
        ans += (j*(j+1))/2;
        ans %= mod;
        j = nxt[j];
    }
}

int main()
{
    int T;
    scanf("%d", &T);
    while (T--)
    {
        ans = 0;
        scanf("%s%s", str, tt);
        int l1 = strlen(str);
        int len = strlen(tt);
        for (int i = 0, j =  len - 1; i <= j; i++, j--)
            swap(tt[i], tt[j]);
        for (int i = 0, j =  l1 - 1; i <= j; i++, j--)
            swap(str[i], str[j]);
        // cout << str << " " << tt << endl;
        getnext(tt);

        kmp(str, tt);
        // for(int i=0; i<=len; i++)
        //     cout << nxt[i] << " ";
        // puts("");        
        printf("%I64d\n", ans);
    }
    return 0;
}

 

posted @ 2017-08-19 22:23  _yxg123  阅读(156)  评论(0编辑  收藏  举报