zoukankan      html  css  js  c++  java
  • 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
    ", ans);
        }
        return 0;
    }
  • 相关阅读:
    brctl 使用说明
    Flash文件系统介绍和平台采用squashfs+ubifs原因
    xargs
    svn的常用命令
    shell中的if用法
    shell中单双引号
    删除文件中的 ^M 字符
    博客园添加live2d看板娘
    IOS 自定义转场动画
    rails
  • 原文地址:https://www.cnblogs.com/yxg123123/p/7398166.html
Copyright © 2011-2022 走看看