zoukankan      html  css  js  c++  java
  • 字符串算法学习笔记

    字符串算法学习笔记

    天坑,大概暑假就能填完了。

    符号使用说民

    一般用(S,T)表示一个字符串

    字符串一般从1开始

    (S[lldots r])表示一个子串

    (Sin T)表示(S)(T)的子串

    题目后的( ext{easy/normal/hard/lunatic})表示题目的难度(大概对应NOIp d1t1+/NOIp d1d2+/弱省省选/强省省选)

    kmp学习笔记

    exkmp

    咕了(

    AC自动机总结

    假设你们都懂AC自动机是啥了

    fail树

    ( ext{fail})树就是连接所有(fail_u)(u)的树。

    考虑到(fail_u)所代表的串(in u)所代表的串

    所以若u所代表的串(in S),则在fail树上u到根的所有节点代表的串也(in S)

    我们来看几个例题学习一下

    P3966 [TJOI2013]单词 (normal)

    题目链接

    将fail树建出来。

    然后将每一个串所走过的位置+1

    然后每一个串的出现次数就是结束位置的fail树中的子树的权值之和。

    代码如下

    #include<bits/stdc++.h>
    #define mp make_pair
    #define pb push_back
    #define fi first
    #define se second
    
    
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef vector<int > vi;
    typedef pair<int ,int > pii;
    const int INF=0x3f3f3f3f, maxn=1000007;
    const ll MOD=1004535809;
    const ll LINF=0x3f3f3f3f3f3f3f3fLL;
    const ll P=19260817;
    
    int n;
    char s[maxn];
    int tr[maxn][26];
    int fail[maxn];
    int num[maxn];
    int tot=1;
    int sum[maxn];
    void ins(char *s,int id){
        int len=strlen(s);
        int u=1;
        for(int i=0;i<len;i++){
            int c=s[i]-'a';
            if(!tr[u][c])tr[u][c]=++tot;
            u=tr[u][c];
            sum[u]++;
        }
        num[id]=u;
    }
    struct edge{
        int to,nxt;
    }e[maxn<<1];
    int head[maxn],tot_e;
    void addedge(int u,int v){
        e[++tot_e]=(edge){v,head[u]};
        head[u]=tot_e;
    }
    queue<int > q;
    void build(){
        for(int i=0;i<26;i++)tr[0][i]=1;
        q.push(1);
        while(!q.empty()){
            int u=q.front();
            q.pop();
            for(int i=0;i<26;i++){
                if(tr[u][i])fail[tr[u][i]]=tr[fail[u]][i],q.push(tr[u][i]);
                else tr[u][i]=tr[fail[u]][i];
            }
        }
        for(int i=2;i<=tot;i++){
            addedge(fail[i],i);
        }
    }
    void dfs(int u,int f){
        for(int i=head[u];i;i=e[i].nxt){
            int v=e[i].to;
            if(v==f)continue;
            dfs(v,u);
            sum[u]+=sum[v];
        }
    }
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%s",s);
            ins(s,i);
        }
        build();
        dfs(1,0);
        for(int i=1;i<=n;i++)printf("%d
    ",sum[num[i]]);
    	return 0;
    }
    
    

    P2414 [NOI2011]阿狸的打字机(hard)

    将所有查询离线并建一个ac自动机。

    这个串的ac自动机事实上很好建。

    遇到P就标记一下,遇到B就跳到他父亲。

    我们考虑一组查询(x,y)表示x在y中出现了多少次

    相当与在trie中把y到根的所有节点+1,然后查询在fail树中的子树之和。

    所以我们dfs一遍trie树,如果我们遍历到一个串y,我们就查询所有它所有串。

    查询子树和我们就对在fail树中dfs序建一棵BIT就行了.

    写起来细节有点多

    #include<bits/stdc++.h>
    #define mp make_pair
    #define pb push_back
    #define fi first
    #define se second
    
    #define y0 pmt
    #define y1 pmtpmt
    #define x0 pmtQAQ
    #define x1 pmtQwQ
    // #define getchar nc
    
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef vector<int > vi;
    typedef pair<int ,int > pii;
    const int INF=0x3f3f3f3f, maxn=200007;
    const ll MOD=1004535809;
    const ll LINF=0x3f3f3f3f3f3f3f3fLL;
    const ll P=19260817;
    char nc(){
        static char buf[100000],*p1=buf,*p2=buf;
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
    }
    inline ll read(){
        ll x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')x=((x<<3)+(x<<1)+ch-'0')%MOD,ch=getchar();
        return x*f;
    }
    void write(int x){
        if(!x)putchar('0');if(x<0)x=-x,putchar('-');
        static int sta[20];register int tot=0;
        while(x)sta[tot++]=x%10,x/=10;
        while(tot)putchar(sta[--tot]+48);
    }
    int tr[maxn][26];
    int fail[maxn];
    int f[maxn];
    int cnt=1,id_n=0;
    int num[maxn];
    int tag[maxn];
    int vis[maxn][26];
    void ins(char *s){
        int u=1,len=strlen(s);
        for(int i=0;i<len;i++){
            if(s[i]=='P'){
                num[++id_n]=u;
                tag[u]=1;
            }else if(s[i]=='B'){
                u=f[u];
            }else {
                int c=s[i]-'a';
                if(!tr[u][c]){tr[u][c]=++cnt;f[tr[u][c]]=u;}
                u=tr[u][c];
            }
        }
    }
    struct edge{
        int to,nxt;
    }e[maxn<<1];
    int head[maxn],tot_e;
    void addedge(int u,int v){
        e[++tot_e]=(edge){v,head[u]};
        head[u]=tot_e;
    }
    queue<int > q;
    void build(){
        for(int i=0;i<26;i++)tr[0][i]=1;
        q.push(1);
        while(!q.empty()){
            int u=q.front();
            q.pop();
            for(int i=0;i<26;i++){
                if(tr[u][i])fail[tr[u][i]]=tr[fail[u]][i],q.push(tr[u][i]);
                else tr[u][i]=tr[fail[u]][i];
            }
        }
        for(int i=2;i<=cnt;i++){
            addedge(fail[i],i);
        }
    }
    int dfn_cnt;
    int dfn[maxn];
    int sz[maxn];
    void dfs1(int u,int f){
        dfn[u]=++dfn_cnt;
        sz[u]=1;
        for(int i=head[u];i;i=e[i].nxt){
            int v=e[i].to;
            if(v==f)continue;
            dfs1(v,u);
            sz[u]+=sz[v];
        }
    }
    struct BIT{
        int t[maxn];
        #define N 200000
        void update(int x,int val){x++;for(int i=x;i<=N;i+=(i&-i))t[i]+=val;}
        int query(int x){x++;int rt=0;for(int i=x;i;i-=(i&(-i)))rt+=t[i];return rt;}
    }T;
    vector<pii > query[maxn];
    int ans[maxn];
    void dfs2(int u){
        // cout<<u<<endl;
        T.update(dfn[u],1);
        if(tag[u]){
            // cout<<u<<' '<<query[u].size()<<endl;
            for(int i=0;i<query[u].size();i++){
                int v=query[u][i].fi;
                ans[query[u][i].se]=T.query(dfn[v]+sz[v]-1)-T.query(dfn[v]-1);
            }
        }
        // cout<<u<<' '<<tag[u]<<endl;
        for(int i=0;i<26;i++){
            if(tr[u][i]&&vis[u][i])dfs2(tr[u][i]);
        }
        T.update(dfn[u],-1);
    }
    char s[maxn];
    int n;
    int main(){
        //freopen(".in","r",stdin);
        //freopen(".out","w",stdout);
        scanf("%s",s);
        ins(s);
        build();
        dfs1(1,0);
        scanf("%d",&n);
        for(int i=1,x,y;i<=n;i++){
            scanf("%d%d",&x,&y);
            query[num[y]].pb(mp(num[x],i));
        }
        dfs2(1);
        for(int i=1;i<=n;i++)printf("%d
    ",ans[i]);
    	return 0;
    }
    
    

    CF1207G Indie Album

    和上一题差不多吧……

    后面补SAM做法……。

    #include<bits/stdc++.h>
    #define mp make_pair
    #define pb push_back
    #define fi first
    #define se second
    
    #define y0 pmt
    #define y1 pmtpmt
    #define x0 pmtQAQ
    #define x1 pmtQwQ
    // #define getchar nc
    
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef vector<int > vi;
    typedef pair<int ,int > pii;
    const int INF=0x3f3f3f3f, maxn=800007;
    const ll MOD=1004535809;
    const ll LINF=0x3f3f3f3f3f3f3f3fLL;
    const ll P=19260817;
    char nc(){
        static char buf[100000],*p1=buf,*p2=buf;
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
    }
    inline ll read(){
        ll x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')x=((x<<3)+(x<<1)+ch-'0')%MOD,ch=getchar();
        return x*f;
    }
    void write(int x){
        if(!x)putchar('0');if(x<0)x=-x,putchar('-');
        static int sta[20];register int tot=0;
        while(x)sta[tot++]=x%10,x/=10;
        while(tot)putchar(sta[--tot]+48);
    }
    int n,m;
    char s[maxn];
    vector<pair<int ,int > > t[maxn];
    void ins1(){
        for(int i=1;i<=n;i++){
            int op;
            char c[2];
            scanf("%d",&op);
            if(op==1){
                scanf("%s",c);
                t[1].pb(mp(c[0]-'a',i+1));
            }else {
                int j;
                scanf("%d%s",&j,c);
                t[j+1].pb(mp(c[0]-'a',i+1));
            }
        }
    }
    int tr[maxn][26];
    int fail[maxn];
    int tot_cnt=1;
    int num[maxn];
    vector<pii > vec[maxn];
    void ins(char *s,int id){
        int u=1,len=strlen(s);
        for(int i=0;i<len;i++){
            int c=s[i]-'a';
            if(!tr[u][c])tr[u][c]=++tot_cnt;
            u=tr[u][c];
        }
        num[id]=u;
    }
    struct edge{
        int to,nxt;
    }e[maxn<<1];
    int head[maxn],tot_e;
    void addedge(int u,int v){
        e[++tot_e]=(edge){v,head[u]};
        head[u]=tot_e;
    }
    queue<int > q;
    void build(){
        for(int i=0;i<26;i++)tr[0][i]=1;
        q.push(1);
        while(!q.empty()){
            int u=q.front();
            q.pop();
            for(int i=0;i<26;i++){
                if(tr[u][i])fail[tr[u][i]]=tr[fail[u]][i],q.push(tr[u][i]);
                else tr[u][i]=tr[fail[u]][i];
            }
        }
        for(int i=2;i<=tot_cnt;i++){
            addedge(fail[i],i);
        }
    }
    int dfn_cnt;
    int dfn[maxn];
    int sz[maxn];
    void dfs1(int u,int f){
        dfn[u]=++dfn_cnt;
        sz[u]=1;
        for(int i=head[u];i;i=e[i].nxt){
            int v=e[i].to;
            if(v==f)continue;
            dfs1(v,u);
            sz[u]+=sz[v];
        }
    
    }
    
    struct BIT{
        int t[maxn];
        #define N 500000
        void update(int x,int val){x++;for(int i=x;i<=N;i+=(i&-i))t[i]+=val;}
        int query(int x){x++;int rt=0;for(int i=x;i;i-=(i&(-i)))rt+=t[i];return rt;}
    }T;
    int ans[maxn];
    void dfs2(int u1,int u2){
        T.update(dfn[u2],1);
        for(int i=0;i<vec[u1].size();i++){
            int v=vec[u1][i].fi;
            ans[vec[u1][i].se]=T.query(dfn[v]+sz[v]-1)-T.query(dfn[v]-1);
        }
        for(int i=0;i<t[u1].size();i++){
            int c=t[u1][i].fi;
            int v=t[u1][i].se;
            dfs2(v,tr[u2][c]);
        }
        T.update(dfn[u2],-1);
    }
    
    int main(){
        //freopen(".in","r",stdin);
        //freopen(".out","w",stdout);
        scanf("%d",&n);
        ins1();
        scanf("%d",&m);
        for(int i=1;i<=m;i++){
            int x;
            scanf("%d%s",&x,s);
            ins(s,i);
            vec[x+1].pb(mp(num[i],i));
        }
        build();
        dfs1(1,0);
        dfs2(1,1);
        for(int i=1;i<=m;i++){
            printf("%d
    ",ans[i]);
        }
    	return 0;
    }
    

    AC自动机上DP

    P4052 [JSOI2007]文本生成器

    (dp[i][j])表示构造一个长为i,匹配到j节点的串的不合法(即没有合法子串)方案数。

    转移显然

    最后拿(26^m)减一下就好了。

    #include<bits/stdc++.h>
    #define mp make_pair
    #define pb push_back
    #define fi first
    #define se second
    
    #define y0 pmt
    #define y1 pmtpmt
    #define x0 pmtQAQ
    #define x1 pmtQwQ
    // #define getchar nc
    
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef vector<int > vi;
    typedef pair<int ,int > pii;
    const int INF=0x3f3f3f3f, maxn=20007;
    const ll MOD=10007;
    const ll LINF=0x3f3f3f3f3f3f3f3fLL;
    const ll P=19260817;
    char nc(){
        static char buf[100000],*p1=buf,*p2=buf;
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
    }
    inline ll read(){
        ll x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')x=((x<<3)+(x<<1)+ch-'0')%MOD,ch=getchar();
        return x*f;
    }
    void write(int x){
        if(!x)putchar('0');if(x<0)x=-x,putchar('-');
        static int sta[20];register int tot=0;
        while(x)sta[tot++]=x%10,x/=10;
        while(tot)putchar(sta[--tot]+48);
    }
    int tr[maxn][26];
    int fail[maxn];
    int dng[maxn];
    int tot=1;
    void ins(char *s){
        int u=1,len=strlen(s);
        for(int i=0;i<len;i++){
            int c=s[i]-'A';
            if(!tr[u][c])tr[u][c]=++tot;
            u=tr[u][c];
        }
        dng[u]=1;
    }
    struct edge{
        int to,nxt;
    }e[maxn<<1];
    int head[maxn],tot_e;
    void addedge(int u,int v){
        e[++tot_e]=(edge){v,head[u]};
        head[u]=tot_e;
    }
    queue<int > q;
    void build(){
        for(int i=0;i<26;i++)tr[0][i]=1;
        q.push(1);
        while(!q.empty()){
            int u=q.front();
            q.pop();
            for(int i=0;i<26;i++){
                if(tr[u][i])fail[tr[u][i]]=tr[fail[u]][i],q.push(tr[u][i]);
                else tr[u][i]=tr[fail[u]][i];
            }
        }
        for(int i=2;i<=tot;i++){
            // addedge(u,fail[u]);
            addedge(fail[i],i);
        }
    }
    
    void dfs(int u,int flag){
        dng[u]|=flag;
        for(int i=head[u];i;i=e[i].nxt){
            int v=e[i].to;
            dfs(v,dng[u]);
        }
    }
    ll qpow(ll a,ll b){
        ll rt=1;
        while(b){
            if(b&1)rt=rt*a%MOD;
            a=a*a%MOD;
            b>>=1;
        }
        return rt;
    
    }
    int n,m;
    char s[maxn];
    int dp[107][maxn];
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            scanf("%s",s);
            ins(s);
        }
        build();
        dfs(1,0);
        dp[0][1]=1;
        for(int i=1;i<=m;i++){
            for(int j=1;j<=tot;j++){
                for(int c=0;c<26;c++){
                    if(!dng[tr[j][c]])dp[i][tr[j][c]]=(dp[i][tr[j][c]]+dp[i-1][j])%MOD;
                }
            }
        }
        ll ans=qpow(26,m);
        for(int i=1;i<=tot;i++){
            ans=(ans-dp[m][i]+MOD)%MOD;
        }
        printf("%lld",ans);
        return 0;
    }
    
    

    杂题

    后缀数据结构学习

  • 相关阅读:
    Jar依赖很多,找不到重复的包??好工具来帮助您
    BHP编译器教程
    MySvn--一个简单单机svn程序源码-delphi开发
    delphi也可以使用C语言脚本 --Picoc脚本语言
    sqlserver,mysql,oracle通用的模拟和改进的全文搜索算法
    EhReport ,CReport改进版本,再次改进 ,V1.31
    Robot Framework(3)——RIDE工具详解
    Robot Framework(2)——简单运行案例
    Robot Framework(1)——环境搭建及安装
    Jenkins(1)—— 部署安装
  • 原文地址:https://www.cnblogs.com/pmt2018/p/12234502.html
Copyright © 2011-2022 走看看