zoukankan      html  css  js  c++  java
  • 7.21 学习笔记

    1 字符串hash

    1.1 Codeforces 955D Scissors

    我们设 (L_i) 表示在第二个字符串(以下称该字符串为 (t) )长度为 (i) 的前缀在第一个字符串(以下称该字符串为 (s) )出现最高左的位置是哪个位置。不难发现,去掉无意义的位置,(L) 这个数组一定是递增的,所以我们可以考虑用双指针来完成这个事情。

    同样,我们可以预处理出 (R_i) 表示长度为 (i) 的后缀在 (s) 中出现最靠右的位置。

    这样,(t) 被分成两半的情况就分别讨论完了,需要注意的是还有一种情况,就是你这个 (t) 可能存在于 (s) 非常靠左的位置或非常靠右的位置,且 (s) 的长度要小于 (t) ,在这种情况下,上面是讨论不到的。所以我们需要额外讨论一下 (t)(s) 中出现的情况。这种情况我们直接取前缀的一段和后缀的一段就可以了。

    代码:

    #include<bits/stdc++.h>
    #define dd double
    #define ld long double
    #define ll long long
    #define uint unsigned int
    #define ull unsigned long long
    #define N 500010
    #define M number
    using namespace std;
    
    const int INF=0x3f3f3f3f;
    const ull mod=13331;
    
    template<typename T> inline void read(T &x) {
        x=0; int f=1;
        char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        x*=f;
    }
    template<typename T> inline T Max(T a,T b){
        return a<b?b:a;
    }
    
    template<typename T> inline T Min(T a,T b){
        return a<b?a:b;
    }
    
    int n,m,L[N],R[N],k;
    char s[N],t[N];
    ull hs[N],ht[N],mpow[N];
    
    inline ull GetHash(ull *h,int l,int r){
        return h[r]-h[l-1]*mpow[r-l+1];
    }
    
    inline void prework(){
        int l,r;l=1;r=1;
        int minn=Min(m,k);
        while(r-l+1<=minn&&r<=n-k){
            ull ha=GetHash(hs,l,r);
            ull hb=GetHash(ht,1,r-l+1);
            if(ha==hb){
                L[r-l+1]=r;
                if(l>1) l--;
                else r++;
            }
            else{l++;r++;}
        }
        for(int i=1;i<=m;i++) if(L[i]<k) L[i]=0;
        l=r=k;
        while(r-l+1<=minn&&r<=n-k&&L[r-l+1]==0){
            ull ha=GetHash(hs,l,r);
            ull hb=GetHash(ht,1,r-l+1);
            if(ha==hb){
                L[r-l+1]=r;
                if(l>1) l--;
                else r++;
            }
            else{l++;r++;}
        }
        l=r=n;
        while(r-l+1<=minn&&l>=k+1){
            ull ha=GetHash(hs,l,r);
            ull hb=GetHash(ht,m-r+l,m);
            if(ha==hb){
                R[r-l+1]=l;
                if(r<n) r++;
                else l--;
            }
            else{l--;r--;}
        }
        for(int i=1;i<=m;i++) if(R[i]>n-k+1) R[i]=0;
        l=r=n-k+1;
        while(r-l+1<=minn&&l>=k+1&&R[r-l+1]==0){
            ull ha=GetHash(hs,l,r);
            ull hb=GetHash(ht,m-r+l,m);
            if(ha==hb){
                R[r-l+1]=l;
                if(r<n) r++;
                else l--;
            }
            else{l--;r--;}
        }
        for(int i=1;i<=m;i++){
            if(!L[i]) L[i]=-INF;
            if(!R[i]) R[i]=INF;
        }
    }
    
    int main(){
        // freopen("my.in","r",stdin);
        // freopen("my.out","w",stdout);
        read(n);read(m);read(k);
        int maxx=Max(n,m);
        mpow[0]=1;for(int i=1;i<=maxx;i++) mpow[i]=mpow[i-1]*mod;
        scanf("%s%s",s+1,t+1);
        for(int i=1;i<=n;i++) hs[i]=hs[i-1]*mod+s[i]-'a';
        for(int i=1;i<=m;i++) ht[i]=ht[i-1]*mod+t[i]-'a';
        prework();
        // printf("L: ");for(int i=1;i<=m;i++) printf("%d ",L[i]);putchar('
    ');
        // printf("R: ");for(int i=1;i<=m;i++) printf("%d ",R[i]);putchar('
    '); 
        for(int i=1;i<=m;i++){
            if(L[i]==-INF||R[m-i]==INF) continue;
            else if(L[i]<R[m-i]){
                printf("Yes
    ");
                printf("%d %d
    ",L[i]-k+1,R[m-i]);
                return 0;
            }
        }
        ull all=GetHash(ht,1,m);
        for(int i=1;i<=n-m+1;i++){
            ull now=GetHash(hs,i,i+m-1);
            if(all==now){
                printf("Yes
    ");
                printf("1 %d
    ",n-k+1);
                return 0;
            }
        }
        printf("No
    ");
        return 0;
    }
    /*
    不能够从两边避免 k ,但是需要防止 k 的情况。
    51 13 11
    cbcbbcbbbbbcccbcccbbbcbbbbbbbbbbbbcbbbcbbcbbbbcbbbb
    bbbbbccbcbbcb
    ans:
    Yes
    3 38
    */
    

    1.2 Codeforces 985F Isomorphic Strings

    这个题我们只需要改变 hash 的方式,把每一个字符单独拿出来,用出现次数来做 hash,这样就可以完成这道题了。同时我们可以利用 multiset 来判断相等,这样可以避免 hash 出错。

    #include<bits/stdc++.h>
    #define dd double
    #define ld long double
    #define ll long long
    #define int long long
    #define uint unsigned int
    #define ull unsigned long long
    #define N 300000
    #define M number
    using namespace std;
    
    const int INF=0x3f3f3f3f;
    const int mod=1e9+7;
    const int base=114514;
    
    template<typename T> inline void read(T &x) {
        x=0; int f=1;
        char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        x*=f;
    }
    
    int n,m,mpow[N],h[26][N];
    char s[N];
    
    inline int GetHash(int *h,int l,int r){
        // printf("l:%d r:%d r-l+1:%d
    ",l,r,r-l+1);
        return ((h[r]-h[l-1]*mpow[r-l+1]%mod)+mod)%mod;
    }
    
    signed main(){
        // freopen("my.in","r",stdin);
        // freopen("my.out","w",stdout);
        read(n);read(m);scanf("%s",s+1);
        mpow[0]=1;for(int i=1;i<N;i++) mpow[i]=(mpow[i-1]*base)%mod;
        for(int i=1;i<=n;i++){
            for(int j=0;j<=25;j++) h[j][i]=(h[j][i-1]*base+1+(s[i]-'a'==j))%mod;
        }
        for(int i=1;i<=m;i++){
            int a,b,c;read(a);read(b);read(c);
            multiset<int> s,t;
            for(int j=0;j<=25;j++){
                // printf("%lld %lld
    ",GetHash(h[j],a,a+c-1),GetHash(h[j],b,b+c-1));
                s.insert(GetHash(h[j],a,a+c-1));
                t.insert(GetHash(h[j],b,b+c-1));
            }
            printf("%s
    ",s==t?"YES":"NO");
        }
    }//
    

    1.3 二维hash darkbzoj2351

    二维 hash 其实和一维 hash 一样,也就是说我们拿第一个质数横着做一遍 hash,然后换一个质数,把 hash 值当成要做 hash 的值,竖着在做一遍 hash,这样就可以做了。

    代码:

    // #include<bits/stdc++.h>
    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<cstdio>
    #include<map>
    #define dd double
    #define ld long double
    #define ll long long
    #define uint unsigned int
    #define ull unsigned long long
    #define N 201
    #define M 2010
    using namespace std;
    
    const int INF=0x3f3f3f3f;
    const ull mod=131;
    const ull base=13331;
    
    template<typename T> inline void read(T &x) {
        x=0; int f=1;
        char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        x*=f;
    }
    
    template<typename T> inline T Max(T a,T b){
        return a<b?b:a;
    }
    
    ull mpow[M],bpow[M];
    
    ull d[M][M],f[M][M];
    // set<ull> S;
    map<ull,int> S;
    
    int m,n,a,b,q,ans[N*10];
    char s[M];
    
    int main(){
    
    
        read(n);read(m);read(a);read(b);int maxx=Max(n,m);
        mpow[0]=bpow[0]=1;
        for(int i=1;i<=maxx;i++){
            mpow[i]=mpow[i-1]*mod;bpow[i]=bpow[i-1]*base;
        }
        for(int i=1;i<=n;i++){
            scanf("%s",s+1);
            for(int j=1;j<=m;j++){
                d[i][j]=d[i][j-1]*mod+s[j]-'0';
            }
        }
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                d[i][j]+=d[i-1][j]*base;
        for(int i=1;i<=n-a+1;i++)
            for(int j=1;j<=m-b+1;j++){
                int x=i+a-1,y=j+b-1;
                ull now=d[x][y]-d[x][j-1]*mpow[y-j+1];
                ull now2=d[i-1][y]-d[i-1][j-1]*mpow[y-j+1];
                ull nowans=now-now2*bpow[x-i+1];
                // if(S.count(nowans)) ans[S[nowans]]=1;
                S[nowans]=1;
            }
        read(q);
        for(int i=1;i<=q;i++){
            ull nowans=0;
            for(int j=1;j<=a;j++){
                ull now=0;
                scanf("%s",s+1);
                for(int k=1;k<=b;k++){
                    now*=mod;now+=s[k]-'0';
                }
                nowans*=base;nowans+=now;
            }
            // printf("i:%d nowans:%llu
    ",i,nowans);
            // S[nowans]=i;
            if(S.count(nowans)) ans[i]=1;
        }
        for(int i=1;i<=q;i++) printf("%d
    ",ans[i]);
    }
    

    1.4 UVA1401 Remember the Word

    显然是一个 dp 。我们设 (f_i) 表示考虑完前 (i) 个字符的方案数,那么转移就是:

    [f_i=sumlimits_{s_{i+1,j}in dictionary}f_j+1 ]

    我们发现这个东西的复杂度在于判断是否在字典里,所以我们不妨反过来做:

    (f_i) 表示考虑完 (s_{i,len}) 的方案数,转移和上面差不多,至于判断是否在字典里,我们可以建一棵 Trie 树来帮助我们判断,因为 Trie 树的节点深度不会超过 (100) ,所以复杂度为 (O(100n))

    代码:

    #include<bits/stdc++.h>
    #define dd double
    #define ld long double
    #define ll long long
    #define uint unsigned int
    #define ull unsigned long long
    #define N 400010
    #define M 110
    using namespace std;
    
    const int INF=0x3f3f3f3f;
    const int mod=20071027;
    
    template<typename T> inline void read(T &x) {
        x=0; int f=1;
        char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        x*=f;
    }
    
    int ch[N][26],tot,End[N],n,f[N];
    char s[N],t[M];
    
    inline void Insert(char *s){
        int len=strlen(s+1),p=0;
        for(int i=1;i<=len;i++){
            int c=s[i]-'a';
            if(!ch[p][c]) ch[p][c]=++tot;
            p=ch[p][c];
        }
        End[p]=1;
    }
    
    
    
    int main(){
        // freopen("my.in","r",stdin);
        // freopen("my.out","w",stdout);
        int test=0;
        while(scanf("%s",s+1)!=EOF){
            test++;
            memset(ch,0,sizeof(ch));
            memset(End,0,sizeof(End));
            read(n);
            for(int i=1;i<=n;i++){
                scanf("%s",t+1);Insert(t);
            }
            memset(f,0,sizeof(f));
            int len=strlen(s+1);f[len+1]=1;
            for(int i=len;i>=1;i--){
                int p=0;
                for(int j=i;j<=len;j++){
                    int c=s[j]-'a';
                    if(!ch[p][c]) break;
                    p=ch[p][c];if(End[p]) (f[i]+=f[j+1])%=mod;
                }
            }
            printf("Case %d: ",test);
            printf("%d
    ",f[1]);
        }
        return 0;
    }
    

    1.5 UVA1519 Dictionary Size

    看到前缀和后缀我们首先想到 Trie 树。我们正向建一棵 Trie 树,反向建一棵 Trie 树。那么答案我们首先认为是两颗 Trie 树的节点个数减 (1) 的乘积。

    不难发现,有一些字符串我们没有统计,就是那些长度为 (1) 的字符串,这是因为我们上面的操作只统计了长度大于等于 (2) 的字符串。与此同时,我们有一些字符串被重复统计,不难发现,重复统计的次数是每一个字符在 Trie 树上的出现次数之积,减去就可以了。

    #include<bits/stdc++.h>
    #define dd double
    #define ld long double
    #define ll long long
    #define uint unsigned int
    #define int long long
    #define ull unsigned long long
    #define N 400010
    #define M 50
    using namespace std;
    
    const int INF=0x3f3f3f3f;
    
    template<typename T> inline void read(T &x) {
        x=0; int f=1;
        char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        x*=f;
    }
    
    char s[M];
    int n,ans,c[M];
    
    struct Trie{
        int p[N][26],tot;
        int cnt[M];
        inline Trie(){tot=0;}
        inline void Insert(char *s){
            int now=0;int len=strlen(s);
            for(int i=0;i<len;i++){
                int k=s[i]-'a';
                if(!p[now][k]){
                    p[now][k]=++tot;
                    if(i){
                        cnt[k]++;
                    }
                }
                now=p[now][k];
            }
        }
        inline void clear(){
            tot=0;memset(p,0,sizeof(p));
            memset(cnt,0,sizeof(cnt));
        }
    };
    Trie t1,t2;
    
    signed main(){
        while(cin>>n){
            for (int i = 0; i < n; i++) {
                scanf("%s", s);
     
                int n = strlen(s);
                if (n == 1)
                    c[s[0] - 'a'] = 1;
                t1.Insert(s);
                reverse(s, s + n);
                t2.Insert(s);
            }
            ans=t1.tot*t2.tot;
            for(int i=0;i<=25;i++){
                if(c[i]) ans++;
                ans-=(t1.cnt[i]*t2.cnt[i]);
            }
            printf("%lld
    ",ans);
            t1.clear();t2.clear();
            ans=0;memset(c,0,sizeof(c));
        }
    }
    

    2 AC自动机

    2.1 P4052 [JSOI2007]文本生成器

    首先关注到不出现,不出现的话考虑用 AC 自动机,主要是借助 Trie 树这个结构。我们简单的取一下补集。

    既然不能出现,那么也就是说不能做到结束节点,更进一步,我们在 Trie 树上走,我们也不能走到一个节点,其所表示的字符串的后缀是这 (n) 个字符串中的一个。换句话说,我们要把所有满足后缀不合法的节点标记一下,怎么标记?我们在建立 AC 自动机的时候把这个节点的 end 与其后缀链接的 end 或一下就可以了。

    然后就比较套路了,我们设 (f_{i,j}) 表示走了 (i) 步,在 Trie 图上的 (j) 节点,方案数。转移就枚举下一步要去哪里即可。然后把每个位置上走了 (m) 步的方案数累加就可以了。

    值得一提的是,Trie 图并不是 DAG ,不用担心在 Trie 图上做 dp 的正确性。

    #include<bits/stdc++.h>
    #define dd double
    #define ld long double
    #define ll long long
    #define uint unsigned int
    #define ull unsigned long long
    #define N 110
    #define M 6100
    using namespace std;
    
    const int INF=0x3f3f3f3f;
    const int mod=1e4+7;
    
    template<typename T> inline void read(T &x) {
        x=0; int f=1;
        char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        x*=f;
    }
    
    struct node{
        int ch[26],end,fail;
    };
    
    int f[N][M],n,m;
    char s[N];
    
    struct AC{
        node p[M];int tot;
    	inline AC(){memset(p,0,sizeof(p));tot=0;}
        inline void Insert(char *s){
            int len=strlen(s),now=0;
            for(int i=0;i<=len-1;i++){
                int k=s[i]-'A';
                if(!p[now].ch[k]) p[now].ch[k]=++tot;
                now=p[now].ch[k];
            }
            p[now].end=1;
        }
        inline void GetFail(){
            queue<int> q;
    		while(q.size()) q.pop();
            for(int i=0;i<=25;i++) if(p[0].ch[i]) q.push(p[0].ch[i]);
            while(q.size()){
                int top=q.front();q.pop();
                for(int i=0;i<=25;i++){
                    if(p[top].ch[i]){
                        p[p[top].ch[i]].fail=p[p[top].fail].ch[i];
                        p[p[top].ch[i]].end|=p[p[p[top].fail].ch[i]].end;
                        q.push(p[top].ch[i]);
                    }
                    else p[top].ch[i]=p[p[top].fail].ch[i];
                }
            }
        }
        inline void DP(){
            f[0][0]=1;
            for(int i=1;i<=m;i++){
                for(int j=0;j<=tot;j++){
                    for(int k=0;k<=25;k++){
                        if(p[p[j].ch[k]].end==1) continue;
                        (f[i][p[j].ch[k]]+=f[i-1][j])%=mod;
                    }
                }
            }
        }
        inline int GetAns(){
            int ans=0;
            for(int i=0;i<=tot;i++){
                ans+=f[m][i];ans%=mod;
            }
            return ans;
        }
    };
    AC ac;
    
    inline int ksm(int a,int b,int mod){
    	int res=1;
    	while(b){
    		if(b&1) (res*=a)%=mod;
    		a=a*a%mod;
    		b>>=1;
    	}
    	return res;
    }
    
    int main(){
    	// freopen("my.in","r",stdin);
    	// freopen("my.out","w",stdout);
    	ios::sync_with_stdio(false);cin.tie(0);
    	// read(n);read(m);
    	cin>>n>>m;
    	for(int i=1;i<=n;i++){
    		cin>>s;
    		ac.Insert(s);
    	}
    	ac.GetFail();ac.DP();
    	int ans=ac.GetAns();
    	// printf("%d
    ",((ksm(26,m,mod)-ans)%mod+mod)%mod);
    	cout<<((ksm(26,m,mod)-ans)%mod+mod)%mod<<"
    ";
    	return 0;
    }
    /*
    update 1:
    row 48 "p[p[top].ch[i]].end|=p[p[top].fail].ch[i];"
    update 2:
    row 101 -> row 100
    update 3
    row 93 -> 92
    */
    

    2.2 P4600 [HEOI2012]旅行问题

    建立 AC 自动机,在 fail 树上求 LCA 就可以了。

    代码:

    #include<bits/stdc++.h>
    #define dd double
    #define ld long double
    #define ll long long
    #define uint unsigned int
    #define ull unsigned long long
    #define N 3000010
    #define M number
    using namespace std;
    
    const int INF=0x3f3f3f3f;
    const ll mod=1e9+7;
    
    template<typename T> inline void read(T &x) {
        x=0; int f=1;
        char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        x*=f;
    }
    
    vector<int> ID[N];
    
    struct node{
        int ch[26],fail,end;
        ll code;
    };
    
    struct edge{
        int to,next;
        inline void intt(int to_,int ne_){
            to=to_;next=ne_;
        }
    };
    edge li[N];
    int head[N],tail;
    
    inline void add(int from,int to){
        li[++tail].intt(to,head[from]);
        head[from]=tail;
    }
    
    struct AC{
        node p[N];int size;
        inline AC(){size=1;}
        inline void Insert(int id,char *s){
            int len=strlen(s);int now=1;
            for(int i=0;i<=len-1;i++){
                int k=s[i]-'a';
                if(!p[now].ch[k]) p[now].ch[k]=++size;
                int last=now;now=p[now].ch[k];
                p[now].code=(p[last].code*26%mod+k)%mod;
                ID[id].push_back(now);
            }
            p[now].end++;
        }
        inline void GetFail(){
            queue<int> q;
            for(int i=0;i<=25;i++){
                if(p[1].ch[i]){q.push(p[1].ch[i]);p[p[1].ch[i]].fail=1;}
                else p[1].ch[i]=1;
            }
            while(q.size()){
                int top=q.front();q.pop();
                for(int i=0;i<=25;i++){
                    if(p[top].ch[i]){
                        p[p[top].ch[i]].fail=p[p[top].fail].ch[i];
                        q.push(p[top].ch[i]);
                    }
                    else p[top].ch[i]=p[p[top].fail].ch[i];
                }
            }
        }
        inline void BuildFailTree(){
            for(int i=2;i<=size;i++){
                // printf("i:%d fail:%d
    ",i,p[i].fail);
                add(p[i].fail,i);
            }
        }
    };
    AC ac;
    
    int n,q;
    char s[N];
    
    int top[N],son[N],siz[N],deep[N],fa[N];
    
    inline void dfs1(int k,int fat){
        deep[k]=deep[fat]+1;siz[k]=1;fa[k]=fat;
        for(int x=head[k];x;x=li[x].next){
            int to=li[x].to;
            if(to==fat) continue;
            dfs1(to,k);
            siz[k]+=siz[to];
            if(siz[son[k]]<siz[to]) son[k]=to;
        }
    }
    
    inline void dfs2(int k,int t){
        top[k]=t;
        if(son[k]) dfs2(son[k],t);
        for(int x=head[k];x;x=li[x].next){
            int to=li[x].to;
            if(to==fa[k]||to==son[k]) continue;
            dfs2(to,to);
        }
    }
    
    inline int GetLca(int a,int b){
        while(top[a]!=top[b]){
            if(deep[top[a]]<deep[top[b]]) swap(a,b);
            a=fa[top[a]];
        }
        if(deep[a]>deep[b]) swap(a,b);
        return a;
    }
    
    int main(){
        // freopen("my.in","r",stdin);
        // freopen("my.out","w",stdout);
        read(n);
        for(int i=1;i<=n;i++){
            scanf("%s",s);ac.Insert(i,s);
        }
        ac.GetFail();ac.BuildFailTree();
        dfs1(1,0);dfs2(1,1);
        read(q);
        for(int i=1;i<=q;i++){
            int a,b,c,d;read(a);read(b);read(c);read(d);
            int p1=ID[a][b-1],p2=ID[c][d-1];
            // printf("p1:%d p2:%d
    ",p1,p2);
            // printf("lca:%d
    ",GetLca(p1,p2));
            printf("%lld
    ",ac.p[GetLca(p1,p2)].code);
        }
        return 0;
    }
    

    3 KMP 算法

    KMP 算法不会考匹配,而会考对 next 数组的理解和运用。

    3.1 HDU3336

    (f_i) 表示以 (i) 结尾的所有的前缀的出现次数,那么显而易见的转移是 (f_i=f_{next_i}+1) ,之所以加 (1) 是整个长度为 (i) 的字符串,所有以 (next_i) 结尾的前缀都会在以 (i) 结尾中出现 (1) 次。

    代码:

    #include<bits/stdc++.h>
    #define dd double
    #define ld long double
    #define ll long long
    #define uint unsigned int
    #define ull unsigned long long
    #define N 200010
    #define M number
    using namespace std;
    
    const int INF=0x3f3f3f3f;
    const int mod=10007;
    
    template<typename T> inline void read(T &x) {
        x=0; int f=1;
        char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        x*=f;
    }
    
    int t,n,nxt[N],f[N],ans;
    char s[N];
    
    int main(){
        read(t);
        while(t--){
            read(n);
            scanf("%s",s+1);
            nxt[1]=0;
            for(int i=2,j=0;i<=n;i++){
                while(j>0&&s[j+1]!=s[i]) j=nxt[j];
                if(s[j+1]==s[i]) j++;
                nxt[i]=j;
            }
            for(int i=1;i<=n;i++){
                f[i]=f[nxt[i]]+1;f[i]%=mod;
                ans+=f[i];ans%=mod;
            }
            printf("%d
    ",ans);
            for(int i=1;i<=n;i++) nxt[i]=f[i]=0;ans=0;
        }
    }
    

    3.2 POJ 2752

    KMP 的题我用字符串 hash 做的,就这样吧。。。

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define dd double
    #define ld long double
    #define ll long long
    #define uint unsigned int
    #define ull unsigned long long
    #define N 400010
    #define M number
    using namespace std;
    
    const int INF=0x3f3f3f3f;
    const ull mod=13331;
    
    template<typename T> inline void read(T &x) {
        x=0; int f=1;
        char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        x*=f;
    }
    
    ull a,b;
    char s[N];
    
    int main(){
        // freopen("my.in","r",stdin);
        // freopen("my.out","w",stdout);
        while(cin>>(s+1)){
            a=b=0;
            ull ji=1;int n=strlen(s+1);
            for(int i=1;i<=n;i++){
                a*=mod;a+=s[i]-'a';
                int j=n-i+1;int siz=n-j;
                b+=ji*(s[j]-'a');ji*=mod;
                if(a==b) printf("%d ",i);
            }
            putchar('
    ');
        }
    }
    
  • 相关阅读:
    线性代数:矩阵行列式
    线性代数:逆变换
    线性代数:线性变换
    线性代数:零空间
    线性代数:向量乘法
    线性代数基础:向量组合
    线性代基础理论:向量
    线性代基础理论:矩阵
    SpringBoot 消费NSQ消息
    将Oracle中的数据放入elasticsearch
  • 原文地址:https://www.cnblogs.com/TianMeng-hyl/p/15183862.html
Copyright © 2011-2022 走看看