zoukankan      html  css  js  c++  java
  • HDU 3336(kmp+dp +HDU 4300

    hdu 3336

    题目:给出一个字符串,问该字符串的每个前缀在字符串中出现的次数之和。

    思路:需要对next数组有足够的理解。设dp[i]表示以i结尾的字符串中出现的总次数(答案),那么首先在next[i]到i之间的前缀不会是对应的后缀,所以该长度的串数量恰好是dp[next[i]]+1。

    UPD:今天又看了一下,感觉之前理解得很不到位....首先dp[i]的意义是以i结尾的后缀在前缀中出现的次数,然后通过next走到到前缀都是该后缀的后缀,但是长度都比该后缀要短.然后这显然不会重复,最后的答案要累加所有dp值(因为他们的位置都是不同的,但是可能是相同的串)

    /*
    * @author:  Cwind
    */
    //#pragma comment(linker, "/STACK:102400000,102400000")
    #include <iostream>
    #include <map>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <functional>
    #include <set>
    #include <cmath>
    using namespace std;
    #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0)
    #define pb push_back
    #define PB pop_back
    #define bk back()
    #define fs first
    #define se second
    #define sq(x) (x)*(x)
    #define eps (1e-6)
    #define IINF (1<<29)
    #define LINF (1ll<<59)
    #define INF (1000000000)
    #define FINF (1e3)
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    typedef pair<ll,ll> P;
    
    const int maxlen=1e6+300;
    int fail[maxlen];
    int T;
    void getFeil(char *s,int *f){
        int len=strlen(s);
        int i=0,j=f[0]=-1;
        while(i<len){
            while(j!=-1&&s[j]!=s[i]) j=f[j];
            f[++i]=++j;
        }
    }
    
    const int mod=10007;
    int n;
    char r[maxlen];
    int dp[maxlen];
    int main(){
        freopen("/home/files/CppFiles/in","r",stdin);
        //freopen("test.in","r",stdin);
        //freopen("test.out","w",stdout);
        cin>>T;
        while(T--){
            scanf("%d %s",&n,r);
            getFeil(r,fail);
            int len=strlen(r);
            dp[0]=0;
            int ans=0;
            for(int i=1;i<=len;i++){
                dp[i]=dp[fail[i]];
                dp[i]++;
                dp[i]%=mod;
                ans+=dp[i];
                ans%=mod;
            }
            cout<<ans<<endl;
        }
        return 0;
    }
    View Code

     hdu 4300

    题目:给你一个加密方法,和一个序列,序列前半部分是加密信息,后半部分是原来的信息,但是后半部分可能缺损(前半部分肯定完整),问可能的最短原串.

    思路:把整个串解密和原串接在一起,用kmp看看前缀和后缀的匹配长度,然后细节上讨论一下即可.

    /*
    * @author:  Cwind
    */
    //#pragma comment(linker, "/STACK:102400000,102400000")
    #include <iostream>
    #include <map>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <functional>
    #include <set>
    #include <cmath>
    using namespace std;
    #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0)
    #define pb push_back
    #define PB pop_back
    #define bk back()
    #define fs first
    #define se second
    #define sq(x) (x)*(x)
    #define eps (1e-6)
    #define IINF (1<<29)
    #define LINF (1ll<<59)
    #define INF (1000000000)
    #define FINF (1e3)
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    typedef pair<ll,ll> P;
    
    const int maxlen=1e6+300;
    int fail[maxlen];
    int T;
    void getFeil(char *s,int *f){
        int len=strlen(s);
        int i=0,j=f[0]=-1;
        while(i<len){
            while(j!=-1&&s[j]!=s[i]) j=f[j];
            f[++i]=++j;
        }
    }
    
    const int mod=10007;
    int n;
    char r[maxlen];
    char tmp[maxlen];
    char d[maxlen];
    char dir[maxlen];
    int dp[maxlen];
    int main(){
        freopen("/home/files/CppFiles/in","r",stdin);
        //freopen("test.in","r",stdin);
        //freopen("test.out","w",stdout);
        cin>>T;
        while(T--){
            scanf("%s",d);
            scanf("%s",r);
            for(int i=0;i<26;i++){
                dir[d[i]-'a']=i+'a';
            }
            int len=strlen(r);
            for(int i=0;i<len;i++){
                tmp[i]=dir[r[i]-'a'];
            }
            tmp[len]=0;
            strcat(tmp,r);
            getFeil(tmp,fail);
            if(fail[len*2]<=len/2){
                printf("%s",r);
                for(int i=fail[len*2];i<len-fail[len*2];i++){
                    printf("%c",tmp[i]);
                }
            }else{
                printf("%s",r);
                int t=len-fail[len];
                if(len%t!=0||(len%t==0&&len/t%2))
                for(int i=len%t;i<t;i++){
                    printf("%c",r[i]);
                }
            }
            puts("");
        }
        return 0;
    }
    View Code
  • 相关阅读:
    成员变量和局部变量
    成员变量和局部变量
    对象和类
    数组
    Scanner--控制台输入
    Java运算符
    Java数据类型
    TextView控件
    Android控件
    注释
  • 原文地址:https://www.cnblogs.com/Cw-trip/p/4824919.html
Copyright © 2011-2022 走看看