首页 > 其他 > 详细

hdu6153 A Secret CCPC网络赛 51nod 1277 KMP

时间:2017-08-19 23:00:20      阅读:273      评论:0      收藏:0      [点我收藏+]

题目链接:

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;
}

 

hdu6153 A Secret CCPC网络赛 51nod 1277 KMP

原文:http://www.cnblogs.com/yxg123123/p/7398166.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!