您的位置:首页 > 编程语言 > C语言/C++

UVALive 4126 (ac自动机做状态类)

2015-10-09 15:40 295 查看
题意:

给定最多10个长度不超过10的子串,让构造长度为n(n<=25)的字符串使得给定的子串都在该串中出现,问这种串有多少。

分析:

暴力是26^25中可能性,那么怎样精简状态,可以定义d[ i ][ j ][ s ]为当前构造的串长为i且已经到达自动机j位置,已经生成的子串状态为s,接着往下构造所能生成的合法串有多少。

状态转移,就是直接暴力枚举一下下一个字母是谁,在自动机中做状态转移。

一开始用ac自动机做状态不是很好理解,j其实是代表着前面走到i位置,所有最大匹配在自动机中为j的串,那么转移也如此。

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <queue>
#include <set>
#include <string>
using namespace std;
typedef long long ll;
#define rep(i,n) for(int i=0;i<(int)n;i++)
#define rep1(i,x,y) for(int i=x;i<=y;i++)

const int maxnnode = 110;
const int sigma_size = 26;
struct Trie{
int ch[maxnnode][sigma_size];
int val[maxnnode],f[maxnnode],last[maxnnode];
int cnt;
void init(){
cnt = 0; memset(ch[0],0,sizeof(ch[0]));
val[0] = 0;
memset(val,0,sizeof(val));
}
int id(char c){return c-'a';}
void insert(char* s,int x){
int n=strlen(s),u=0;
rep(i,n){
int c = id(s[i]);
if(!ch[u][c]){
ch[u][c]=++cnt;
val[cnt]=0;
memset(ch[cnt],0,sizeof(ch[cnt]));
}
u = ch[u][c];
}
val[u] = x;
}
void build(){
f[0] = last[0]=0;
queue<int> Q;
rep(i,sigma_size){
if(ch[0][i]) Q.push(ch[0][i]),f[ch[0][i]]=last[ch[0][i]]=0;
}
while(!Q.empty()){
int u=Q.front(); Q.pop();
rep(i,sigma_size){
if(!ch[u][i]){
ch[u][i] = ch[f[u]][i];
continue;
}
int v = ch[u][i];
f[v] = ch[f[u]][i];
last[v] = (val[f[v]] ? f[v] : last[f[v]]);
Q.push(v);
}
}
}
int print_(int u){
cnt = 0;
while(u) {
cnt|=(1<<(val[u]-1));
u = last[u];
}
return cnt;
}
}ac;
const int maxn = 26;
ll d[maxn][maxnnode][(1<<10)+10];
int n,m;
ll dp(){
memset(d
,0,sizeof(d
));
for(int j=0;j<maxnnode;j++) d
[j][(1<<m)-1]=1;
int te = ac.cnt;
for(int i=n-1;i>=0;i--)
rep1(j,0,te)
for(int s=0;s<(1<<m);s++){
d[i][j][s] = 0;
rep(k,sigma_size){
int c = ac.ch[j][k];
int ts = ac.print_(ac.val[c] ? c : ac.last[c]);
d[i][j][s]+=d[i+1][c][(s|ts)];
}
}
return d[0][0][0];
}
vector<char> aa;
void print_(int i,int j,int s){
if(i == n){
rep(i,aa.size()) cout<<aa[i]; cout<<endl;
return ;
}
rep(k,sigma_size){
int c = ac.ch[j][k];
int ts = ac.print_(ac.val[c] ? c : ac.last[c]);
if(d[i+1][c][s|ts]) {
aa.push_back('a'+k);
print_(i+1,c,s|ts);
aa.pop_back();
}
}
}
set<string> vvis;
int main()
{
int kase=1;
vvis.clear();
while(scanf("%d %d",&n,&m)==2 && n){
vvis.clear();
ac.init();
int rm = 0;
rep(i,m){
char s[30];
scanf("%s",s);
string te = s ;
if(!vvis.count(te)){
ac.insert(s,++rm);
vvis.insert(te);
}
}
m = rm;
ac.build();
ll ans = dp();
aa.clear();
printf("Case %d: %lld suspects\n",kase++,ans);
if(ans <= 42){
print_(0,0,0);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  algorithm c++ UVA