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'); 提示成功,但客户端仍然连接 ...
随机推荐
- Debug 介绍
Debug 设置
- tableview隐藏多余分割线
- (void)setExtraCellLineHidden: (UITableView *)tableView{ UIView *view =[ [UIView alloc]init]; view. ...
- Java基础(37):Java中日期的显示与格式定值----Date与SimpleDateFormat的试用
使用 Date 和 SimpleDateFormat 类表示时间 在程序开发中,经常需要处理日期和时间的相关数据,此时我们可以使用 java.util 包中的 Date 类.这个类最主要的作用就是获取 ...
- C++初学者 const使用详解
关于C++中的const关键字的用法非常灵活,而使用const将大大改善程序的健壮性,参考了康建东兄的const使用详解一文,对其中进行了一些补充,写下了本文. 1. const常量 如: cons ...
- 当执行php脚本时用户关闭浏览器会发生什么?
2008年8月16日 1,152 views 发表评论 阅读评论 如果一段php脚本执行插入数据到mysql的操作. 一般情况下,由于php脚本在服务器上执行,此时用户虽然关闭了浏览器,但是服务器端的 ...
- JQuery获取和设置Select选项常用方法总结
1.获取select 选中的 text: $("#cusChildTypeId").find("option:selected").text(); $(&quo ...
- 1. 星际争霸之php面向对象(一)
题记==============================================================================本php设计模式专辑来源于博客(jymo ...
- zw版【转发·台湾nvp系列Delphi例程】HALCON DirectShow
zw版[转发·台湾nvp系列Delphi例程]HALCON DirectShow unit Unit1;interfaceuses Windows, Messages, SysUtils, Varia ...
- php获取网页中图片并保存到本地
php获取网页中图片并保存到本地的代码,将网页中图片保存本地文件夹: save_img("http://www.jbxue.com" ?>
- 衣明志是个SB
面试碰到衣明志,问了些傻逼问题,尼玛就是一不折不扣的蠢驴. 这个人太能装了,而且水平也不咋地.