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. win7 winsxs精简 cmd 脚本之 再次 改进版

    dos时代菜鸟发表于 2012-7-24 http://bbs.wuyou.net/forum.php?mod=viewthread&tid=255200&highlight=win7 ...

  2. Java中的JDK动态代理

    所谓代理,其实就是相当于一个中间人,当客户端需要服务端的服务时,不是客户直接去找服务,而是客户先去找代理,告诉代理需要什么服务,然后代理再去服务端找服务,最后将结果返回给客户. 在日常生活中,就拿买火 ...

  3. BIOS MCSDK 2.0 学习笔记(二)————使用Platform Library创建工程

    [TOC] Platform Library提供了一组适用于开发板的API函数.我们可以使用它来快速入手开发板. 1.启动CCS,建立一个空的工程 2.添加include路径 "C:\Pro ...

  4. SQLServer解析xml到Oracle

    写了一个程序:根据状态位读取SQLserver 中的一张表,下载其中一个字段的值,这个值是XML类型的,然后把这个XML文件的内容插入到另一Oracle数据库,并更新SQLServer表的标志位,表示 ...

  5. chrome经常崩溃解决过程

    之前chrome常崩溃,也没有找到原因,就将就着用吧,一直用到今天,今天连续几次崩了,突然想到,难道是因为我访问的域名没有解析(能想到这个,是因为今天分配公司域名测试的时候常输错),于是就输入一个不存 ...

  6. mysql数据库的导入导出

    当我们在操作数据库的时候,难免会遇到数据导入导出的一些操作,今天突然学到了这个知识点,特意来给大家分享. 我用的是data的这条数据 1.使用数据 mysql> use data; Databa ...

  7. 无废话SharePoint入门教程二[SharePoint发展、工具及术语]

    一.前言 1.由于上一篇文章的标题命名失误,此篇标题写给百度搜索”什么是SharePoint”. 2.关于什么是SharePoint,请参见本人的第一篇文章:http://www.cnblogs.co ...

  8. android模块混淆打包时,泛型丢失

    现象:lib模块中写了一个泛型接口,在混淆之后泛型消失,提示"Error:(67, 79) 错误: 类型 ******* 不带有参数" 解决:混淆时把泛型给混淆掉了,在progua ...

  9. pthreads 2.0.10 test

    CentOS 6.3 cd /root mkdir pthreads //get php-5.6 and install zts version wget cn2.php.net/get/php-5. ...

  10. algorithm -- 基本介绍

    为学习算法和使用.实践 GIT & GitHub ,而写此系列. 我使用的编译器是 visual studio community 2015 低版本的VS打不开GitHub中的解决方案,拷贝代 ...