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;
    }
  • 相关阅读:
    .Net中的设计模式——Decorator模式
    PetShop的系统架构设计
    PetShop数据访问层之消息处理
    对象的封装与C#的类
    Flash/Flex学习笔记(46):正向运动学
    Flash/Flex学习笔记(43):动量守恒与能量守恒
    win7下恢复“经典任务栏”/“快速启动栏”,关闭“窗口自动最大化”
    Flash/Flex学习笔记(50):3D线条与填充
    图片的javascript延时加载
    Flash/Flex学习笔记(51):3维旋转与透视变换(PerspectiveProjection)
  • 原文地址:https://www.cnblogs.com/hxer/p/5268135.html
Copyright © 2011-2022 走看看