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'); 提示成功,但客户端仍然连接 ...
随机推荐
- struts标签小记
1.<s:iterator>标签的 奇偶数行使用不同样式 <s:iterator id="list" value="#request.listq&qu ...
- 转:python webdriver API 之层级定位
在实际的项目测试中,经常会有这样的需求:页面上有很多个属性基本相同的元素 ,现在需要具体定位到其中的一个.由于属性基本相当,所以在定位的时候会有些麻烦,这时候就需要用到层级定位.先定位父元素,然后再通 ...
- With as 递归查询
use TEST create table Provinces ( pro_Id ,), pro_Name nvarchar(), pro_Code nvarchar(), pro_PId int ) ...
- [转] java书籍(给Java程序猿们推荐一些值得一看的好书 + 7本免费的Java电子书和教程 )
7本免费的Java电子书和教程 1. Thinking in Java (Third Edition) 本书的作者是Bruce Eckel,它一直都是Java最畅销的免费电子书.这本书可以帮助你系统的 ...
- [原创]java WEB学习笔记49:文件上传基础,基于表单的文件上传,使用fileuoload 组件
本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当 ...
- Python学习总结5:数据类型及转换
Python提供的基本数据类型主要有:整型.浮点型.字符串.列表.元组.集合.字典.布尔类型等等. Python可以用一些数据类型函数,直接进行转换: 函数 ...
- MAC开发NDK非常的简单
转自:http://www.cnblogs.com/jarrah/archive/2013/03/15/2961892.html 附带CDT的下载:http://www.eclipse.org/cdt ...
- linux下利用nginx部署python网站
首先目标机器需要安装python nginx uwsgi,其次,需要给Nginx写配置文件,大体内容如下,具体内容可见 http://blog.cn2p.com/web-server/nginx-uw ...
- C++之路进阶——codevs1036(商务旅行)
1036 商务旅行 题目描述 Description 某首都城市的商人要经常到各城镇去做生意,他们按自己的路线去做,目的是为了更好的节约时间. 假设有N个城镇,首都编号为1,商人从首都出发,其他各城镇 ...
- 面向切面编程AOP:基于注解的配置
Aop编程就是面向编程的羝是切面,而切面是模块化横切关注点. -切面:横切关注点,被模块化的特殊对象. -通知:切面必须要完成的工作 -目标:被通知的对象 -代理:向目标对象应用通知之后创建的对象. ...