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. hibernate hql

    hibernate在使用hql进行select count(*) from ObjectA left join fetch apath 时会报错,多余的left join去掉即可.

  2. loadrunner json

    Action(){ web_custom_request("JRPT_WriteLog", //VuGen中树形视图中显示的名称 "Url=url", //请求 ...

  3. html标签

    HTML常用标签 首先要知道html标签的一些特点: 1.类似“<关键字>”这样由尖括号包关键字组成,例如<html>,<div>…… 2.一般是成对出现的,由开始 ...

  4. 十天精通CSS3学习笔记 part3

    第8章 CSS3中的变形与动画(上) 变形--旋转 rotate() 旋转rotate()函数通过指定的角度参数使元素相对原点进行旋转.它主要在二维空间内进行操作,设置一个角度值,用来指定旋转的幅度. ...

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

    http://www.imooc.com/learn/33 第1章 初识CSS3 什么是CSS3? CSS3是CSS2的升级版本,3只是版本号,它在CSS2.1的基础上增加了很多强大的新功能. 目前主 ...

  6. Python学习笔记之抽象

    一.创建函数 >>> import math >>> x=1 >>> y=math.sqrt >>> callable(x) # ...

  7. Github windows客户端简单使用教程

    1. 首先到官网下载Github客户端,官网地址:https://desktop.github.com/ 2. 点击上图红框的按钮开始下载客户端. 3. 双击下载好的客户端,开始安装. 双击之后出现一 ...

  8. 《精通C#》第十二章 Linq

    Linq是在.Net3.5之后首次引入的,这种查询语言简单易学,可用范围非常广泛在学着之前,一直用在数据库操作之上,但是在学习这节课之后才发现,凡是实现泛型的接口类型都可以使用linq,简单来说就是实 ...

  9. WebForm复杂控件

    Calendar   日历: FileUpdate 文件上传: Image 图片,可以直接给URL: Repeater: HeaderTemplate - 在加载开始执行一遍 ItemTemplate ...

  10. tfs中如何创建团队项目及如何操作团队项目

    创建团队项目集合 tfs server管理控制台\团队项目集合页面.选择'创建集合'链接,按向导即可创建项目集合. 创建团队项目 创建好团队项目集合后,就要开始创建团队项目了. 进入vs,连接上tfs ...