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. Markdown渲染后文章标题收缩控件

    文章首发于szhshp的第三边境研究所(szhshp.org), 转载请注明 一个让Markdown-Post的标题拥有Collapse功能的JS 直接把鼠标放在这篇文章下方的header上,点击标题 ...

  2. Linux下漏洞提权

    Linux下的漏洞提权 linux下一般都是系统漏洞提权,分为以下几个步骤:

  3. 【原创】基于SVM作短期时间序列的预测

    [面试思路拓展] 对时间序列进行预测的方法有很多, 但如果只有几周的数据,而没有很多线性的趋势.各种实际的背景该如何去预测时间序列? 或许可以尝试下利用SVM去预测时间序列,那么如何提取预测的特征呢? ...

  4. archlinux 安装手记

    Wiki常用软件 https://wiki.archlinux.org/index.php/Common_Applications -> 移动硬盘等的自动挂载 pacman -S gvfs-af ...

  5. php 使用curl模拟登录discuz以及模拟发帖

    <?php$discuz_url = 'http://127.0.0.1/discuz/';//论坛地址$login_url = $discuz_url .'logging.php?action ...

  6. VHDL学习之模块调用

    http://wenku.baidu.com/link?url=SsRPUVQAOKDR8yWfDhQlceCwfZQkI-KQMLFKTDGAh3KAPr2NwEgvj0d_EZjdnsB99Upp ...

  7. 我的毕业设计——基于安卓和.NET的笔记本电脑远程控制系统

    手机端: 电脑端:    答辩完成后会开放代码.

  8. UITableViewCell 顶格

    首先在ViewDidLoad 或者ViewWillAppear里边写 if ([_tabView respondsToSelector:@selector(setSeparatorInset:)]) ...

  9. SAX和DOM解析的区别

    XML和JSon是ios解析文件的两种形式, 两种方法各有千秋. 1>. XML分为SAX和DOM两种方式 SAX是按顺序逐行读取文件, 查找到符合条件的内容时就会停止, 而DOM是讲内容一次性 ...

  10. [IOS 开发] 懒加载 (延迟加载) 的基本方式,好处,代码示例

    懒加载的好处: 1> 不必将创建对象的代码全部写在viewDidLoad方法中,代码的可读性更强 2> 每个属性的getter方法中分别负责各自的实例化处理,代码彼此之间的独立性强,松耦合 ...