zoukankan      html  css  js  c++  java
  • 字符串相关算法合集

    ...日后会慢慢补(flag!)先来讲讲基本的

    一.字符串Hash

    将字符串用一个数表示,常用的写法有:

    1.自然溢出

    2.单Hash

    3.双Hash

    前两个会被精心构造的串卡掉,最后一个虽然目前卡不掉,但是出题人可以卡你常数。

    所以这个算法很Naive?不是的

    我们来看一道题 bzoj1014

    用splay维护字符串的最长公共前缀,那么问题来了,没有一种OI比赛中常用的数据结构能维护一个动态的字符串

    这时字符串哈希就派上了用场

    我们用一个哈希值来表示字符串

    在splay上跑一个二分查找就好了

    具体的Hash方法网上都有

    这里仅介绍思想

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<queue>
    #include<set>
    #include<map>
    #include<stack>
    #define ll unsigned long long
    #define pi 3.14
    #define eps 1e-9
    #define inf 2147483233
    #define m(a) memset(a,0,sizeof(a))
    #define M(a) memset(a,127,sizeof(a))
    #define REP(i,m,n) for(int i=1;i<=n;i++)
    #define DWN(i,n,m) for(int i=n;i>=1;i++)
    #define lowbit(x) x&(-x)
    #define POJ(n) while(~scanf("%d",&n) && n)
    using namespace std;
    int n;
    inline int read()
    {
        int x=0,f=1;
        char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch)){x=10*x+ch-'0';ch=getchar();}
        return x*f;
    }
    inline void write(int x)
    {
        int num=0;
        char buf[15];
        while(x)buf[++num]=(x%10)+'0',x/=10;
        while(num)putchar(buf[num--]);
        putchar('
    ');
    }
    ll powe[150000];
    void makepow()
    {
        int i;
        for(powe[0]=1,i=1;i<140142;i++)powe[i]=powe[i-1]*131;
    }
    const int maxn=140142;
    char str[maxn];
    struct SplayTree
    {
        int rt,Size;
        int son[maxn][2],f[maxn],size[maxn];
        ll val[maxn],hsh[maxn];
        char s[maxn];
        inline void pushup(int x){size[x]=size[son[x][0]]+size[son[x][1]]+1;hsh[x]=hsh[son[x][0]]+powe[size[son[x][0]]]*s[x]+powe[size[son[x][0]]+1]*hsh[son[x][1]];}
        inline void Rotate(int x,int type)
        {
            int y=f[x];
            son[y][!type]=son[x][type];
            f[son[x][type]]=y;
            f[x]=f[y];
            if(f[x])son[f[y]][son[f[y]][1]==y]=x;  
            son[x][type]=y;
            f[y]=x;
            size[x]=size[y],hsh[x]=hsh[y];
            pushup(y);
        }
        inline void splay(int x,int goal)
        {
            while(f[x]!=goal)  
            {  
                if(f[f[x]]==goal)  
                {  
                    if(son[f[x]][0]==x)Rotate(x,1);  
                    else Rotate(x,0);  
                }  
                else 
                {  
                   int y=f[x],z=f[y];  
                   if(son[z][0]==y)  
                   {  
                      if(son[y][0]==x)Rotate(y,1),Rotate(x,1);  
                      else Rotate(x,0),Rotate(x,1);  
                   }  
                   else 
                   {  
                       if(son[y][1]==x)Rotate(y,0),Rotate(x,0);  
                       else Rotate(x,1),Rotate(x,0);  
                   }  
                }  
            }  
            if(goal==0) rt=x;
        }
        inline int rank(int x,int k)
        {
            if(k<=size[son[x][0]]) return rank(son[x][0],k);  
            else if(k==size[son[x][0]]+1) return x;  
            else return rank(son[x][1],k-size[son[x][0]]-1); 
        }
        inline int build(int l,int r,int id)
        {
            if(l>r)return 0;
            int x=++Size,mid=(l+r)>>1;
            f[x]=id;
            s[x]=str[mid];
            son[x][0]=build(l,mid-1,x);  
            son[x][1]=build(mid+1,r,x);  
            pushup(x);  
            return x;
        }
        inline void insert(int k,char val)  
        {  
            int x=rank(rt,k),y=rank(rt,k+1);  
            splay(x,0),splay(y,x);  
            s[++Size]=val;  
            f[Size]=y,son[y][0]=Size;  
            pushup(Size);  
            pushup(y);  
            pushup(x);  
        }
        inline void change(int k,int val)
        {
            int x=rank(rt,k);  
            splay(x,0);  
            s[x]=val;  
            pushup(x);
        }
        inline int bisearch(int kx,int ky)
        {  
            int l=0,r=n,mid;  
            while(l<=r)  
            {  
                mid=l+r>>1;  
                if(ky+mid>n+2)  
                {  
                    r=mid-1;  
                    continue;  
                }  
                int x=rank(rt,kx-1),y=rank(rt,kx+mid);  
                splay(x,0),splay(y,x);  
                ll temp=hsh[son[y][0]];  
                x=rank(rt,ky-1),y=rank(rt,ky+mid);  
                splay(x,0),splay(y,x);  
                if(temp==hsh[son[y][0]])l=mid+1;  
                else r=mid-1;  
            }  
            return r;  
        }  
    }splay;
    int main()
    {
        int m,i,j,k,x,y;
        char op[10],val[10];
        scanf("%s%d",str+1,&m);  
        makepow();
        n=strlen(str+1);
        splay.rt=splay.build(0,n+1,0);  
        for(i=1;i<=m;i++)  
        {  
            scanf("%s",op);  
            if(op[0]=='I')  
            {  
                scanf("%d%s",&x,val);  
                splay.insert(x+1,val[0]);  
                n++;  
            }  
            else if(op[0]=='R')  
            {  
                scanf("%d%s",&x,val);  
                splay.change(x+1,val[0]);  
            }  
            else 
            {  
                scanf("%d%d",&x,&y);  
                if(x>y)  swap(x,y);  
                if(x!=y)  
                    printf("%d
    ",splay.bisearch(x+1,y+1));  
                else 
                    printf("%d
    ",n-x+1);  
            }  
        }  
        return 0;  
    }
    bzoj1014
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair <int, int> pii;
    const int N = 2e6 + 5;
    const int seed = 131;
    int mod[2] = {1000000007, 1000000009};
    char S[N]; //输入字符串
    int F[2][N]; //seed ^ a
    int pre[2][N];
    int n, g, w;
    int tim, vis[N], ans[N];
    map <pii, int> cnt;
    
    void pre_init(){ //deal with seed ^ n
        for(int t = 0; t <= 1; t++){
            F[t][0] = 1;
            for(int i = 1; i < N; i++){
                F[t][i] = (LL)F[t][i-1] * seed % mod[t];
            }
        }
    }
    
    pii Hash(string s){ //Hash a string
        int ret[2] = {0};
        int len = s.size();
        for(int t = 0; t <= 1; t++){
            for(int i = 0; i < len; i++){
                ret[t] = ((LL) ret[t] * seed + s[i]) % mod[t];
            }
        }
        return pii(ret[0], ret[1]);
    }
    
    pii Hash(int l, int r)
    {
        int ret[2];
        for(int t = 0; t <= 1; t++){
            ret[t] = (pre[t][r] - (LL)pre[t][l-1] * F[t][r-l+1] % mod[t] + mod[t]) % mod[t];
        }
        return pii(ret[0], ret[1]);
    }
    
    void pre_solve(){
        int len = strlen(S + 1);
        for(int t = 0; t <= 1; t++){
            pre[t][0] = 0;
            for(int i = 1; i <= len; i++){
                pre[t][i] = ((LL)pre[t][i-1] * seed + S[i]) % mod[t];
            }
            for(int j = len + 1, i = 1; i <= w - 1; i++, j++){
                pre[t][j] = ((LL)pre[t][j-1] * seed + S[i]) % mod[t];
            }
        }
    }
    
    bool check(int id){
        tim++;
        int l = id, r = id + w - 1;
        for(int i = 1; i <= n; i++, l += w, r += w){
            pii t = Hash(l, r);
            if(!cnt.count(t)) return 0; //目标串中没有这个子串
            int p = cnt[t];
            if(vis[p] == tim) return 0; //目标串出现了大于1次
            vis[p] = tim; ans[i] = p;
        }
        printf("YES
    ");
        for(int i = 1; i <= n; i++) cout << ans[i] <<" "; cout << endl;
        return 1;
    }
    
    int main()
    {
        pre_init();
        scanf("%d%d%s", &n, &w, S+1);
        pre_solve();
        scanf("%d", &g);
        for(int i = 1; i <= g; i++){
            scanf("%s", S);
            pii t = Hash(S);
            cnt[t] = i;
        }
        bool mark = 0;
        for(int i = 1; i <= w; i++){
            if(check(i)){
                mark = 1;
                break;
            }
        }
        if(mark == 0){
            printf("NO
    ");
        }
        return 0;
    }
    双哈希代码(源网)

    模数之一要用19260817这个大质数

    有奇效

    二.K(kan)M(mao)P(pian)

    一类用于单字符串匹配的O(n+m)的算法

    解释也不是很好讲

    直接上模板吧

    #include<cstdio>
    #include<string>
    #include<iostream>
    using namespace std;
    int p[101];
    int main()
    {
        string a,b;
        cin>>a>>b;
        int n=a.length(),m=b.length();
        a=" "+a;b=" "+b;
        int j=0;
        for(int i=2;i<=m;i++)
        {
                while(j>0&&b[j+1]!=b[i])j=p[j];
                if(b[j+1]==b[i])j++;
                p[i]=j;
                }
        j=0;
        for(int i=1;i<=n;i++)
        {
                while(j>0&&b[j+1]!=a[i])j=p[j];
                if(b[j+1]==a[i])j++;
                if(j==m){printf("%d",i-m+1);break;}
                }
        return 0;
    }
    View Code

    三.AC自动机

    /*多么希望AC和自动能够换一下*/

    就是在Trie树上跑KMP

    每个点都有一个Fail指针表示如果这个点匹配不上跳到哪个地方

    四.字符串dp

    1.O(n^2)可以过的dp

    设计状态一般至少为dp[i][j]表示第一个串的前i个和第二个串的前j个怎么这么样

    2.AC自动机上的dp

    两种做法:第一个是构建Fail树,跑树形dp

    另外一种不能在Fail树上做的,一般有一维表示"当前在AC自动机的x号节点上"

  • 相关阅读:
    程其襄实变函数与泛函分析课件
    谢惠民答案
    谢惠民 数学分析习题课讲义 答案
    谢惠民数学分析习题课讲义下册参考解答
    重磅! 谢惠民下册参考解答已经全部完成, 共 473 页!
    各大高校考研试题参考解答目录2020/06/21版
    Jenkins Pipeline审批
    Zabbix监控DHCP作用域(json格式数据)
    MDT通过UserExit.vbs调用PowerShell脚本获取变量
    MDT通过PowerShell脚本自定义变量(自定义计算机名)
  • 原文地址:https://www.cnblogs.com/Kong-Ruo/p/8127695.html
Copyright © 2011-2022 走看看