zoukankan      html  css  js  c++  java
  • hdu 3336 Count the string KMP+DP优化

    Count the string

    Problem Description
    It is well known that AekdyCoin is good at string problems as well as number theory problems. When given a string s, we can write down all the non-empty prefixes of this string. For example:
    s: "abab"
    The prefixes are: "a", "ab", "aba", "abab"
    For each prefix, we can count the times it matches in s. So we can see that prefix "a" matches twice, "ab" matches twice too, "aba" matches once, and "abab" matches once. Now you are asked to calculate the sum of the match times for all the prefixes. For "abab", it is 2 + 2 + 1 + 1 = 6.
    The answer may be very large, so output the answer mod 10007.
     
    Input
    The first line is a single integer T, indicating the number of test cases.
    For each case, the first line is an integer n (1 <= n <= 200000), which is the length of string s. A line follows giving the string s. The characters in the strings are all lower-case letters.
     
    Output
    For each case, output only one number: the sum of the match times for all the prefixes of s mod 10007.
     
    Sample Input
    1 4 abab
     
    Sample Output
    6
    思路:(字符串从1开始)
    1.可以直接套用kmp的getfail()来得到f[i],但是这里的f[i]并不是p[i] = p[f[i]],而是在第i位失配情况下从第i位退回到第f[i]位判断是否能配对;这样就需要一直f[i]在f[i] = p[f[i]]时累加,直至i到0结束;由于里面使用的是朴素的mp匹配,即并没有进行优化f[i],KMP的时间复杂度为O(n),但是在循环查找的过程中,由于每个点最坏的情况就是倒退到1,这样最坏的时间复杂度就为O(n^2),能在78ms内过纯属数据..太弱了
    #include <bits/stdc++.h>
    using namespace std;
    #define mod 10007
    const int maxn=2e5+7;
    int f[maxn];
    char s[maxn];
    void getfail(char *T)
    {
        int i=1,j=0,n=strlen(T+1);f[1]=0;
        while(i<n){
            if(j==0||T[i]==T[j])//确定当前位,给下一位一个机会
                ++i,++j,f[i]=j;
            else
                j=f[j];
        }
    }
    int main()
    {
        int T,n;
        cin>>T;
        while(T--)
        {
            scanf("%d%s",&n,s+1);
            getfail(s);
            int cnt=0;
            for(int i=1;i<=n;i++){
                int t=0;
                for(int j=i;j;j=f[j])
                    if(s[i]==s[j]) // 相等才累加;
                        ++t;
                cnt=(cnt+t)%mod;
            }
            cout<<cnt<<endl;
        }
        return 0;
    }

    2.上面的是正版的KMP...对于每一个f[i]其实只是一个试探可能性,并不确定是否相等;那么我们就利用前面的相等的f[i]来确定与当前位相等的f[i],这样就不需要病了f[i]来找是否p[i] = p[f[i]]了,并且这是一个基础,即一个子结构。用一个数组记录下前一个p[f[i]]的前缀串,直接+1即可;

    62ms,时间复杂度为O(n)

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 2e5+7;
    const int mod = 10007;
    char p[N];
    int f[N],dp[N];
    void getfail()
    {
        int j=0,n=strlen(p+1);
        f[1]=0;
        for(int i = 2;i <= n;i++){
           while(j && p[j+1] != p[i]) j = f[j];//确定当前位置是前面前缀串的最后一位;
           if(p[i] == p[j+1]) j++;
           f[i] = j;
        }
    }
    int main()
    {
        int n,T;
        scanf("%d",&T);
        while(T--){
            scanf("%d",&n);
            scanf("%s", p+1);
            getfail();
            int ans = 0;
            dp[0] = 0;
            for(int i = 1;i <= n;i++){
                dp[i] = dp[f[i]] + 1;
                ans = (ans+dp[i])%mod;
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    2019-2020-1 20191326《信息安全专业导论》第四周学习总结
    如何在大学里脱颖而出
    2019-2020-1 20191326 《信息安全专业导论》第三周学习总结
    2019-2020-1 20191326《信息安全专业导论》第二周学习总结
    师生关系
    Idea Terminal中配置git和maven命令
    bootstrapTable 设置行样式
    Jquery 遍历数组
    Java 截取字符串
    Tomcat 部署项目访问方式处理及部署多个项目
  • 原文地址:https://www.cnblogs.com/hxer/p/5268135.html
Copyright © 2011-2022 走看看