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. 采用MANIFEST.MF之jar报错ClassNotFoundException解法

    检查n多遍也试了n多次,证明下面是MANIFEST.MF文件正确写法: Manifest-Version: 1.0 Premain-Class: cn.yandz.monitor.SizeOfObje ...

  2. 数据库 MySQL安装图解

    MySQL安装图解 一.MYSQL的安装 1.打开下载的mysql安装文件,双击运行mysql-5.5.40-win32.msi. 2.选择安装类型,有"Typical(默认)". ...

  3. ActiveReports中如何使用Excel数据源

    ActiveReports支持的数据源类型非常多,无论是常用的Oracle数据库.SQL Server.mySQL,还是开源的PostgreSQL,只要是具有ODBC驱动的数据库都可以正常使用,本文讲 ...

  4. Windows下 VM12虚拟机安装OS X 10.11 和VM TOOLS

    Windows下虚拟机安装Mac OS X —– VMware Workstation12安装Mac OS X 10.11 本文即将介绍WIN虚拟MAC的教程.完整详细教程(包含安装中的一些问题) [ ...

  5. 十天精通CSS3学习笔记 part2

    第6章 征服CSS3选择器(上) 属性选择器 在HTML中,通过各种各样的属性可以给元素增加很多附加的信息.例如,通过id属性可以将不同div元素进行区分. 在CSS2中引入了一些属性选择器,而CSS ...

  6. java-方法练习

    一.定义方法的最主要的两个步骤: 1.先明确结果(即返回值类型要先明确) 2. 在实现功能时是否有未知内容参与运算,即明确函数的参数列表(参数类型,参数个数) 例如:定义一个九九乘法表的功能.  思路 ...

  7. springMVC 错误页面配置

    在Spring MVC应用程序中,404 error code 被合适的配置.web.xml文件中配置如下所示: <!-- spring mvc start --> <servlet ...

  8. 学习PYTHON之路, DAY 6 - PYTHON 基础 6 (模块)

    一 安装,导入模块 安装: pip3 install 模块名称 导入: import module from module.xx.xx import xx from module.xx.xx impo ...

  9. SQL Server附加数据库问题

    SQL Server附加数据库时,遇到如下问题:“如果升级全文目录,请单加“添加目录”,然后找到它并选择它.基于全文升级选项,全文索引将为“已导入”.” 解决方法: 选择数据库文件所在目录,右键-&g ...

  10. oracle initialization or shutdown in progress解决方法

    [解决方法]   SQL> connect sys/hope as sysdba 已连接. SQL> shutdown normal ORA-01109: 数据库未打开     已经卸载数 ...