LA 4126 Password Suspects
问题描述:给定m个模式串,计数包含所有模式串且长度为n的字符串的数目。
数据范围:模式串长度不超过10,m <= 10, n <= 25,此外保证答案不超过1015。
分析:既然要计数给定长度且满足给定条件的字符串的数目,自然想到搜索,通过枚举每一位的字符缩减问题规模。这里有两个问题:
(1)枚举代价太高,最坏情况下需要2526次操作。
(2)先枚举出完整串再验证其是否满足条件效率太低。
通过观察,我们发现若完整字符串合法,那么在字符串构造时,每个模式串的前缀作为原串的后缀出现。为此我们考虑在搜索字符串时,
记录字符串的后缀信息,这里存储的后缀应该足够长使得若原串的某个后缀能够匹配某模式串的前缀,那么我们记录的后缀的后缀也能够
匹配。
考虑将所有模式串构造成一颗trie树,考虑trie上的状态转移:nex[i][j]表示编号为i的前缀(节点)在其后拼接上字符'a' + j后所得的串
的后缀在trie中能够匹配的最长的前缀节点编号。
并且用state[i]表示从trie根到i节点构成的串的所有后缀能够匹配模式串的集合。
我们用dp[u][S][l]标识当前枚举原字符串的第i个字符,在此之前已经匹配的模式串集合为S,当前串的后缀能够匹配trie中最深的节点编号为l,
那么可以更新dp:
for each i in 'a' to 'z':
next_pointer = nex[l][i]
dp[u][S][l] += dp[u + 1][S | state[next_pointer]][next_pointer]
通过使用动态规划可以解决问题(1),由于状态不超过26 * 210 * 102,且状态转移代价为26,因此总复杂度不超过2602* 210。
后缀实现对整棵trie的前缀匹配,这点类似于AC自动机,实现的同样是单文本串对多模式串的匹配。
- #include <algorithm>
- #include <cstdio>
- #include <cstring>
- #include <string>
- #include <queue>
- #include <map>
- #include <set>
- #include <ctime>
- #include <cmath>
- #include <iostream>
- #include <assert.h>
- #define pi acos(-1.)
- using namespace std;
- typedef long long ll;
- const int int_inf = 0x3f3f3f3f;
- const ll ll_inf = 1ll << ;
- const int INT_INF = (int)((1ll << ) - );
- const int mod = 1e6 + ;
- const double double_inf = 1e30;
- typedef unsigned long long ul;
- #pragma comment(linker, "/STACK:102400000,102400000")
- #define max(a, b) ((a) > (b) ? (a) : (b))
- #define min(a, b) ((a) < (b) ? (a) : (b))
- #define mp make_pair
- #define st first
- #define nd second
- #define keyn (root->ch[1]->ch[0])
- #define lson (u << 1)
- #define rson (u << 1 | 1)
- #define pii pair<int, int>
- #define pll pair<ll, ll>
- #define pb push_back
- #define type(x) __typeof(x.begin())
- #define foreach(i, j) for(type(j)i = j.begin(); i != j.end(); i++)
- #define FOR(i, s, t) for(int i = (s); i <= (t); i++)
- #define ROF(i, t, s) for(int i = (t); i >= (s); i--)
- #define dbg(x) cout << x << endl
- #define dbg2(x, y) cout << x << " " << y << endl
- #define clr(x, i) memset(x, (i), sizeof(x))
- #define maximize(x, y) x = max((x), (y))
- #define minimize(x, y) x = min((x), (y))
- #define low_bit(x) ((x) & (-x))
- inline int readint(){
- int x;
- scanf("%d", &x);
- return x;
- }
- inline int readstr(char *s){
- scanf("%s", s);
- return strlen(s);
- }
- class cmpt{
- public:
- bool operator () (const int &x, const int &y) const{
- return x > y;
- }
- };
- int Rand(int x, int o){
- //if o set, return [1, x], else return [0, x - 1]
- if(!x) return ;
- int tem = (int)((double)rand() / RAND_MAX * x) % x;
- return o ? tem + : tem;
- }
- void data_gen(){
- srand(time());
- freopen("in.txt", "w", stdout);
- int times = ;
- printf("%d\n", times);
- while(times--){
- int n = Rand(, ), m = Rand(, );
- printf("%d %d\n", n, m);
- FOR(i, , n){
- FOR(j, , m) printf("%c", Rand(, ) + 'a');
- putchar('\n');
- }
- n = Rand(min(, n), ), m = Rand(min(, m), );
- printf("%d %d\n", n, m);
- FOR(i, , n){
- FOR(j, , m) printf("%c", Rand(, ) + 'a');
- putchar('\n');
- }
- }
- }
- struct cmpx{
- bool operator () (int x, int y) { return x > y; }
- };
- int debug = ;
- int dx[] = {-, , , };
- int dy[] = {, , -, };
- //-------------------------------------------------------------------------
- const int maxn = ;
- const int sigma_size = ;
- ll dp[][ << ][maxn * maxn];
- int nex[maxn * maxn][sigma_size];
- int state[maxn * maxn];
- int info[maxn * maxn];
- int tot;
- map<string, int> mapi;
- struct Trie{
- int ch[maxn * maxn][sigma_size];
- int idx(char c) { return c - 'a'; }
- int sz;
- void init() { clr(ch[], ); sz = ; clr(info, ); }
- void insert(char *s){
- int u = ;
- while(*s){
- int v = ch[u][idx(*s)];
- if(!v) { ch[u][idx(*s)] = v = ++sz; clr(ch[sz], ); }
- u = v;
- ++s;
- }
- if(!info[u]) info[u] = ++tot;
- }
- char tem[];
- int k;
- void dfs1(int u){
- FOR(i, , sigma_size - ){
- int v = ch[u][i];
- if(!v) continue;
- tem[k++] = i + 'a', tem[k] = '\0';
- mapi[string(tem)] = v;
- dfs1(v);
- --k;
- }
- }
- void dfs2(int u){
- FOR(i, , sigma_size - ){
- int v = ch[u][i];
- if(!v) continue;
- tem[k++] = i + 'a', tem[k] = '\0';
- FOR(j, , k - ){
- string str = string(tem + j);
- if(mapi.find(str) != mapi.end() && info[mapi[str]]) state[v] |= << (info[mapi[str]] - );
- }
- FOR(j, , sigma_size - ){
- tem[k++] = j + 'a', tem[k] = '\0';
- int ok = ;
- FOR(z, , k - ){
- string str = string(tem + z);
- if(mapi.find(str) != mapi.end()){
- nex[v][j] = mapi[str];
- ok = ;
- break;
- }
- }
- if(!ok) nex[v][j] = ;
- --k;
- }
- dfs2(v);
- --k;
- }
- }
- int S;
- void getNext(){
- mapi.clear();
- k = , dfs1();
- k = , clr(state, ), dfs2();
- FOR(i, , sigma_size - ) nex[][i] = ch[][i];
- }
- }trie;
- ll power(ll a, ll p){
- ll ans = ;
- while(p){
- if(p & ) ans *= a;
- p >>= 1ll;
- a = a * a;
- }
- return ans;
- }
- int n, m;
- char mt[maxn][maxn];
- ll dfs(int u, int S, int l){
- if(dp[u][S][l] != -) return dp[u][S][l];
- if(u == n) return dp[u][S][l] = S == (( << tot) - );
- if(S == ( << tot) - ) return dp[u][S][l] = power(, n - u);
- ll tem = ;
- FOR(i, , sigma_size - ){
- int next_pointer = nex[l][i];
- int next_S = S | state[next_pointer];
- tem += dfs(u + , next_S, next_pointer);
- }
- return dp[u][S][l] = tem;
- }
- char buf[maxn << ];
- int k;
- void printAns(int u, int S, int l){
- if(!dp[u][S][l]) return;
- if(u == n){
- buf[k] = '\0';
- puts(buf);
- return;
- }
- FOR(i, , sigma_size - ){
- int next_pointer = nex[l][i];
- int next_S = S | state[next_pointer];
- buf[k++] = i + 'a';
- printAns(u + , next_S, next_pointer);
- --k;
- }
- }
- //-------------------------------------------------------------------------
- int main(){
- //data_gen(); return 0;
- //C(); return 0;
- debug = ;
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
- if(debug) freopen("in.txt", "r", stdin);
- //freopen("out.txt", "w", stdout);
- int kase = ;
- while(~scanf("%d%d", &n, &m) && n){
- FOR(i, , m - ) scanf("%s", mt[i]);
- trie.init(), tot = ;
- FOR(i, , m - ) trie.insert(mt[i]);
- trie.getNext();
- clr(dp, -);
- ll ans = dfs(, , );
- printf("Case %d: %lld suspects\n", ++kase, ans);
- if(ans <= ) k = , printAns(, , );
- }
- //////////////////////////////////////////////////////////////////////////////////////////////////////////////
- return ;
- }
code:
LA 4126 Password Suspects的更多相关文章
- DP(记忆化搜索) + AC自动机 LA 4126 Password Suspects
题目传送门 题意:训练指南P250 分析:DFS记忆化搜索,范围或者说是图是已知的字串构成的自动机图,那么用 | (1 << i)表示包含第i个字串,如果长度为len,且st == (1 ...
- 沉迷AC自动机无法自拔之:[UVALive 4126] Password Suspects
图片加载可能有点慢,请跳过题面先看题解,谢谢 一看到这么多模式串就非常兴奋,又是\(AC\)自动机 题目就是要求:经过 \(n\) 个节点,把所有单词都遍历一遍的方案数,和那道题差不多嘛 所以这样设: ...
- UVALive - 4126 Password Suspects (AC自动机+状压dp)
给你m个字符串,让你构造一个字符串,包含所有的m个子串,问有多少种构造方法.如果答案不超过42,则按字典序输出所有可行解. 由于m很小,所以可以考虑状压. 首先对全部m个子串构造出AC自动机,每个节点 ...
- java实现 蓝桥杯 算法训练 Password Suspects
问题描述 在年轻的时候,我们故事中的英雄--国王 Copa--他的私人数据并不是完全安全地隐蔽.对他来说是,这不可接受的.因此,他发明了一种密码,好记又难以破解.后来,他才知道这种密码是一个长度为奇数 ...
- BUAA Summer Practice 2017 #1 字符串专场
https://vjudge.net/contest/262753#overview C - Regular Number HDU - 5972 bitset temp, temp[i]=1表示 此前 ...
- 获取在线人数 CNZZ 和 51.la
string Cookies = string.Empty; /// <summary> /// 获取在线人数 (51.la统计器) /// </summary> /// &l ...
- 西安电子科技大学第16届程序设计竞赛 E Xieldy And His Password
链接:https://www.nowcoder.com/acm/contest/107/E来源:牛客网 Xieldy And His Password 时间限制:C/C++ 1秒,其他语言2秒 空间限 ...
- 打开程序总是会提示“Enter password to unlock your login keyring” ,如何成功关掉?
p { margin-bottom: 0.1in; line-height: 120% } 一.一开始我是按照网友所说的 : rm -f ~/.gnome2/keyrings/login.keyrin ...
- your password has expired.to log in you must change it
今天应用挂了,log提示密码过期.客户端连接不上. 打开mysql,执行sql语句提示密码过期 执行set password=new password('123456'); 提示成功,但客户端仍然连接 ...
随机推荐
- nc:a test cmd for TCP HTTP
docker 上需要nc 测试环境--internet上搜集了一些资料 ---------------------------------------------------------------- ...
- PostgreSQL Replication之第十章 配置Slony(2)
10.2 理解 Slony如何工作 在我们开始复制我们的第一个数据库之前,我们想深入Slony的架构.理解这是如何工作的是非常重要的,否则,将不可能以一种有用的和合理的方法使用这个软件.与事务日志流不 ...
- HDU 4064 Carcassonne(插头DP)(The 36th ACM/ICPC Asia Regional Fuzhou Site —— Online Contest)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4064 Problem Description Carcassonne is a tile-based ...
- Java Switch(String)
package shb.java.test; /** * switch支持字符串 * @Package:shb.java.test * @Description: * @author shaobn * ...
- JQ 获取单选按钮选中的值
==========================html 代码 <input type="radio" style="float: left " on ...
- java 虚拟机工具
jps 命令 可以查询开启了rmi服务的远程虚拟机进程状态. -v jvm参数. jstat -gcutil命令 [cangyue@/System/Library/Frameworks/JavaVM. ...
- springmvc+spring+mybatis分页查询实例版本2.0
先在改成纯利用js进行分页,首先查询出所有记录,初始化通过jquery控制只知显示首页内容,创建页面切换功能的函数,每次显示固定的内容行并把其他内容行隐藏,这样只需要一次提交就可以实现分页,但是仍有缺 ...
- 夺命雷公狗---node.js---10之POST的接收
首先我们在项目下创建一个表单,代码如下所示: <!DOCTYPE html> <html lang="en"> <head> <meta ...
- CDC
CDC中最重要的问题是metastability问题. 加入Synchronizer来进行异步时钟的同步,两级的Sync,第二级仍然会出现亚稳态的概率由MTBF决定. MTBF:mean time b ...
- win7 64位系统下 PL/SQL无法连接的问题
第一步:下载oracle客户端 由于 PLSQL Developer 没有64位版本,所以在64位系统上运行该程链接64位Oracle时就会报错,笔者为这个问题纠结了好几天,后来通过请教Google ...