AC自动机

UVa 11468  Substring

AC自动机+概率DP。

注意要补全不存在的边。

为什么要补全不存在的边呢?补全以后可以直接找到状态的转移,即从所有子节点就可以实现所有状态转移。

#include<iostream>
#include<vector>
#include<cmath>
#include<map>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<queue>
#include<string>
#define INF 1000000000LL
#define ll long long
#define maxnode 4000+5
#define sigma_size 62
using namespace std;
struct Tire
{
    ],end[maxnode],fail[maxnode];
    int root,L;
    int newnode()
    {
        memset(ch[L],,sizeof(ch[L]));
        end[L++]=;
        ;
    }
    void init()
    {
        L=;
        fail[]=;
        end[]=;
        root=newnode();
    }
    int idx(char c)
    {
        if('a'<=c&&c<='z') return c-'a';
        ;
        ;
    }
    void insert(char* word)
    {
        ;
        ; word[i]; ++i)
        {
            int x=idx(word[i]);
            if(!ch[now][x])
                ch[now][x]=newnode();
            now=ch[now][x];
        }
        end[now]=;
    }
    void build()
    {
        queue<int> que;
        ; i<sigma_size; ++i)
        {
            ][i])
            {
                que.push(ch[][i]);
                fail[ch[][i]]=;
            }
        }
        while(!que.empty())
        {
            int q=que.front();
            que.pop();
            ; i<sigma_size; ++i)
            {
                int u=ch[q][i];
                if(!u)
                {
                    ch[q][i]=ch[fail[q]][i];
                    continue;
                }
                int v=fail[q];
                que.push(u);
                while(v&&!ch[v][i]) v=fail[v];
                fail[u]=ch[v][i];
                end[u]|=end[fail[u]];
            }
        }
    }
};
Tire ac;
];
][];
][];
];
double dp(int now,int L)
{
    if(!L) return 1.0;
    if(vis[now][L]) return f[now][L];
    vis[now][L]=true;
    f[now][L]=0.0;
    ; i<sigma_size; ++i)
        if(cha[i])
        {
            int u=ac.ch[now][i];
            if(!ac.end[u])
                f[now][L]+=pro[i]*dp(u,L-);
        }
    return f[now][L];
}
int main()
{
    ;
    //freopen("read.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    scanf("%d",&T);
    while(T--)
    {
        int k;
        scanf("%d",&k);
        ac.init();
        memset(vis,,sizeof(vis));
        memset(cha,,sizeof(cha));
        ; i<k; ++i)
        {
            ];
            scanf("%s",word);
            ac.insert(word);
        }
        ac.build();
        int n;
        scanf("%d",&n);
        memset(pro,,sizeof(pro));
        ; i<n; ++i)
        {
            ];
            double p;
            scanf("%s%lf",word,&p);
            ]);
            cha[q]=true;
            pro[q]=p;
        }
        int L;
        scanf("%d",&L);
        ,L);
        printf("Case #%d: %.6lf\n",++kase,ans);
    }
    ;
}

HDU 2825 Wireless Password

AC自动机+状态压缩DP

求长度为n的字符串中包含超过k个模式串的个数。

dp[i][j][k]表示长为i,当前状态为j时的字符串包括k个串时的个数,k为集合。

状态压缩使每个串唯一,而不必考虑重复。串可以重叠而考虑AC自动机。

另外注意如果当前dp为0,那就不用刷表了。

#include<iostream>
#include<vector>
#include<cmath>
#include<map>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<queue>
#include<string>
#define ll long long
#define maxnode 105
#define sigma_size 26
#define maxn 100
#define MOD 20090717
using namespace std;
int n,m,K;
int countBit(int val)
{
    ;
    while(val)
    {
        cnt+=val%;
        val/=;
    }
    return cnt;
}
struct Tire
{
    int ch[maxnode][sigma_size],end[maxnode],fail[maxnode];
    int root,L;
    int newnode()
    {
        memset(ch[L],,sizeof(ch[L]));
        end[L++]=;
        ;
    }
    void init()
    {
        L=;
        fail[]=;
        end[]=;
        root=newnode();
    }
    int idx(char c)
    {
        return c-'a';
    }
    void insert(char* word,int p)
    {
        ;
        ; word[i]; ++i)
        {
            int x=idx(word[i]);
            if(!ch[now][x])
                ch[now][x]=newnode();
            now=ch[now][x];
        }
        end[now]=<<p;
    }
    void build()
    {
        queue<int> que;
        ; i<sigma_size; ++i)
        {
            ][i])
            {
                que.push(ch[][i]);
                fail[ch[][i]]=;
            }
        }
        while(!que.empty())
        {
            int q=que.front();
            que.pop();
            ; i<sigma_size; ++i)
            {
                int u=ch[q][i];
                if(!u)
                {
                    ch[q][i]=ch[fail[q]][i];
                    continue;
                }
                int v=fail[q];
                que.push(u);
                while(v&&!ch[v][i]) v=fail[v];
                fail[u]=ch[v][i];
                end[u]|=end[fail[u]];
            }
        }
    }
    ][maxn][(<<)+];
    int solve()
    {
        memset(dp,,sizeof(dp));
        dp[][][]=;
        ; i<n; ++i)
        {
            ; j<L; ++j)
            {
                ; k<(<<m); ++k)
                    if(dp[i][j][k])
                    {
                        ; l<; ++l)
                        {
                            int u=ch[j][l];
                            ][u][k|end[u]];
                            res+=dp[i][j][k];
                            res%=MOD;
                        }
                    }
            }
        }
        ;
        ; j<(<<m); ++j)
            if(countBit(j)>=K)
            {
                ; i<L; ++i)
                {
                    ans+=dp[n][i][j];
                    ans%=MOD;
                }
            }
        return ans;
    }
};
Tire ac;
int main()
{
    while(scanf("%d%d%d",&n,&m,&K)!=EOF)
    {
        if(!n&&!m&&!K) break;
        ac.init();
        ; i<m; ++i)
        {
            ];
            scanf("%s",word);
            ac.insert(word,i);
        }
        ac.build();
        printf("%d\n",ac.solve());
    }
    ;
}

POJ 3691 DNA repair

AC自动机+DP

问修改最少字符使得串中不含模式子串。

dp[i][j]表示当前是当串中第j个位置是第i个节点状态时的最优解。

当c不是结束节点的时候,c表示从i转移到的状态

dp[i][j]=min{dp[c][j+1]+1}//如果此时需要修改

dp[i][j]=min{dp[c][j+1]}//如果此时不修改

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
#define ll long long
using namespace std;
;
;
;
struct Tire
{
    int ch[maxnode][sigma_size];
    int end[maxnode],fail[maxnode];
    int sz;
    int newnode()
    {
        memset(ch[sz],,sizeof(ch[sz]));
        fail[sz]=;
        end[sz++]=;
        ;
    }
    void init()
    {
        sz=;
        newnode();
    }
    int idx(char c)
    {
        ;
        ;
        ;
        ;

    }
    void insert(char *word)
    {
        ;
        ; word[i]; ++i)
        {
            int x=idx(word[i]);
            if(!ch[now][x])
                ch[now][x]=newnode();
            now=ch[now][x];
        }
        end[now]=;
    }
    void build()
    {
        queue<int> que;
        ; i<sigma_size; ++i)
        {
            ][i];
            if(u)
            {
                fail[u]=;
                que.push(u);
            }
        }
        while(!que.empty())
        {
            int q=que.front();
            que.pop();
            ; i<sigma_size; ++i)
            {
                int u=ch[q][i],v=fail[q];
                if(!u)
                {
                    ch[q][i]=ch[v][i];
                    continue;
                }
                que.push(u);
                while(v&&!ch[v][i]) v=fail[v];
                fail[u]=ch[v][i];
                end[u]|=end[fail[u]];
            }
        }
    }
};
][];
][];
];
int N;
Tire ac;
int dp(int now,int L)
{
    ;
    if(vis[now][L]) return f[now][L];
    vis[now][L]=true;
    f[now][L]=inf;
    ; i<; ++i)
    {
        int y=ac.idx(str[L]);
        int u=ac.ch[now][i];
        if(!ac.end[u])
        {
            )!=inf)
                f[now][L]=min(f[now][L],dp(u,L+)+);
            )!=inf)
                f[now][L]=min(f[now][L],dp(u,L+));
        }
    }
    return f[now][L];
}
int main()
{
    ;
    while(scanf("%d",&n)&&n)
    {
        ];
        ac.init();
        memset(vis,,sizeof(vis));
        ; i<=n; ++i)
        {
            scanf("%s",word);
            ac.insert(word);
        }
        scanf("%s",str);
        ac.build();
        N=strlen(str);

        printf("Case %d: ",++kase);
        ,);
        if(ans==inf) puts("-1");
        else printf("%d\n",ans);
    }
    ;
}

字典树

POJ 3630 Phone List

问有没有一个电话号是另一个电话号的前缀。

典型的trie树,时间复杂度是10n。注意不要边读入边判断。否则像12、2这样就判不出来。

#include<cstdio>
#include<vector>
#include<algorithm>
#include<queue>
#include<cstring>
#define LL unsigned int
using namespace std;
;
;
struct Tire
{
    int ch[maxnode][sigma_size];
    int end[maxnode];
    int sz;
    int newnode()
    {
        memset(ch[sz],,sizeof(ch[sz]));
        end[sz]=;
        return sz++;
    }
    void init()
    {
        sz=;
        newnode();
    }
    bool insert(char *word,int v)
    {
        ;
        ; word[i]; ++i)
        {
            ';
            if(!ch[now][x])
                ch[now][x]=newnode();
            now=ch[now][x];
            if(end[now]&&end[now]!=v)
                return false;
        }
        end[now]=v;
        return true;
    }
};
Tire tree;
][];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n;
        scanf("%d",&n);
        bool ok=true;
        tree.init();
        ; i<=n; ++i)
        {
            scanf("%s",numb[i]);
            if(ok&&!tree.insert(numb[i],i))
                ok=false;
        }
        ; i<=n&&ok; ++i)
        {
            if(!tree.insert(numb[i],i))
                ok=false;
        }
        if(ok) puts("YES");
        else puts("NO");
    }
    ;
}

POJ 1204 Word Puzzles

在一个字符矩阵中寻找出现的字符串,并输出头字符的位置和方向。

可以用字典树来做。枚举每个位置再枚举方向,这样每次遍历一个字符串看是否出现了模式串。

#include<cstdio>
#include<vector>
#include<algorithm>
#include<queue>
#include<cstring>
#define LL unsigned int
using namespace std;
*+;
;
][];
int C,L,W;
bool judge(int x,int y)
{
    <=x&&x<L&&<=y&&y<C;
}
int ax,ay,d;
][];
][]= {{-,},{-,},{,},{,},{,},{,-},{,-},{-,-}};
struct Tire
{
    int ch[maxnode][sigma_size];
    int end[maxnode];
    int sz;
    int newnode()
    {
        memset(ch[sz],-,sizeof(ch[sz]));
        end[sz]=;
        return sz++;
    }
    void init()
    {
        sz=;
        newnode();
    }
    int idx(char c)
    {
        return c-'A';
    }
    void insert(char *word,int v)
    {
        ;
        ; word[i]; ++i)
        {
            int x=idx(word[i]);
            )
                ch[now][x]=newnode();
            now=ch[now][x];
        }
        end[now]=v;
    }
    void find(int x,int y)
    {
        ;
        )
        {
            int c=idx(mat[x][y]);
            now=ch[now][c];
            ) break;
            if(end[now])
            {
                ans[end[now]][]=ax;
                ans[end[now]][]=ay;
                ans[end[now]][]=d;
                end[now]=;
            }
            x+=dir[d][];
            y+=dir[d][];
            if(!judge(x,y)) break;
        }
    }
    void find(int x,int y,int now)
    {
         )return;
        )
        {
            ans[end[now]][]=ax;
            ans[end[now]][]=ay;
            ans[end[now]][]=d;
            end[now]=;
        }
        if(!judge(x,y)) return;
        find(x+dir[d][],y+dir[d][],ch[now][idx(mat[x][y])]);
    }
};
Tire tree;
int main()
{
    while(scanf("%d%d%d",&L,&C,&W)!=EOF)
    {
        ; i<L; ++i)
            scanf("%s",mat[i]);
        tree.init();
        ; i<=W; ++i)
        {
            ];
            scanf("%s",str);
            tree.insert(str,i);
        }
        ; i<L; ++i)
            ; j<C; ++j)
                ; k<; ++k)
                {
                    ax=i;
                    ay=j;
                    d=k;
                    tree.find(i,j);
                }
        ; i<=W; ++i)
            printf(],ans[i][],ans[i][]+'A');
    }
    ;
}

ACM 字符串 题目整理的更多相关文章

  1. ACM 矩阵题目整理

    先从最基础的矩阵快速幂加速递推开始. HDU 1005 Number Sequence |f[n-2],f[n-1]|* |0 B| =|f[n-1], B*f[n-2]+A*f[n-1]|=|f[n ...

  2. 【好好补题,因为没准题目还会再出第三遍!!】ACM字符串-组合数学(官方题解是数位DP来写)

    ACM字符串 .长度不能超过n .字符串中仅包含大写字母 .生成的字符串必须包含字符串“ACM”,ACM字符串要求连在一块! ok,是不是很简单?现在告诉你n的值,你来告诉我这样的字符串有多少个 输入 ...

  3. Noip往年题目整理

    Noip往年题目整理 张炳琪 一.历年题目 按时间倒序排序 年份 T1知识点 T2知识点 T3知识点 得分 总体 2016day1 模拟 Lca,树上差分 期望dp 144 挺难的一套题目,偏思维难度 ...

  4. NOIp初赛题目整理

    NOIp初赛题目整理 这个 blog 用来整理扶苏准备第一轮 csp 时所做的与 csp 没 有 关 系 的历年 noip-J/S 初赛题目,记录了一些我从不知道的细碎知识点,还有一些憨憨题目,不定期 ...

  5. ACM - 动态规划专题 题目整理

    CodeForces 429B  Working out 预处理出从四个顶点到某个位置的最大权值,再枚举相遇点,相遇的时候只有两种情况,取最优解即可. #include<iostream> ...

  6. ACM 暴力搜索题 题目整理

    UVa 129 Krypton Factor 注意输出格式,比较坑爹. 每次要进行处理去掉容易的串,统计困难串的个数. #include<iostream> #include<vec ...

  7. ACM金牌选手整理的【LeetCode刷题顺序】

    算法和数据结构知识点图 首先,了解算法和数据结构有哪些知识点,在后面的学习中有 大局观,对学习和刷题十分有帮助. 下面是我花了一天时间花的算法和数据结构的知识结构,大家可以看看. 后面是为大家 精心挑 ...

  8. BZOJ 题目整理

    bzoj 500题纪念 总结一发题目吧,挑几道题整理一下,(方便拖板子) 1039:每条线段与前一条线段之间的长度的比例和夹角不会因平移.旋转.放缩而改变,所以将每条轨迹改为比例和夹角的序列,复制一份 ...

  9. C和C++字符串处理整理

    在刷leetcode题目的过程中,发现自己对于c和c++字符串的处理并不是很拿手,处理起来比较费劲,而且,算法题似乎很中意字符串的处理,有很多题目都涉及到它.字符串处理比较基础,但是很重要,因此,整理 ...

随机推荐

  1. Toolbar设置回退箭头的方法

    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); //关键下面两句话,设置了回 ...

  2. iOS CommonCrypto 对称加密 AES ecb,cbc

    CommonCrypto 为苹果提供的系统加密接口,支持iOS 和 mac 开发: 不仅限于AES加密,提供的接口还支持其他DES,3DES,RC4,BLOWFISH等算法, 本文章主要讨论AES在i ...

  3. ADO.NET 使用通用数据库操作类Database (SQL Server)

    一.Web.config配置 <connectionStrings> <add name="constr_name" connectionString=" ...

  4. swift_初始化器的使用

    //: Playground - noun: a place where people can play import Cocoa ***************************结构体与Cla ...

  5. vue 2.0

    vue2.0 据说也出了很久了,博主终于操了一次实刀. 整体项目采用  vue +  vue-router +  vuex (传说中的vue 全家桶 ),构建工具使用尤大大推出的vue-cli 项目是 ...

  6. SEO之网站稳定

    周未给大伙推荐个电影 :<环太平洋> http://947kan.com/movie/kehuan/45659/ 主要讲述了人类对抗从太平洋海底的时空裂缝不断传送过来的大怪兽,保卫家园的故 ...

  7. Jquery想说爱你不容易

    JQuery是一套跨浏览器的JavaScript库,简化HTML与JavaScript之间的操作.由John Resig在2006年1月的BarCamp NYC上发布第一个版本.目前是由 Dave M ...

  8. php HTTP Auth

    if (!isset($_SERVER['PHP_AUTH_USER']) || $_SERVER['PHP_AUTH_USER'] != 'kuser' || $_SERVER['PHP_AUTH_ ...

  9. hibernate连接数据库的步骤

    三个准备 一.导包   mysql二.在默认src下创建hibernate.cfg.xml   1.创建xml文件,命名为hibernate.cfg.xml 2.添加约束   (在org.hibern ...

  10. Maven的配置