[JSOI2009]密码 [AC自动机]
题面
首先看到这题就知道随便暴枚
只要是多项式算法都能过
先常规建AC自动机
注意被别的单词包含的单词没有存在的价值
剩余单词状压
大力dp f[长度][节点编号][状态]
\(ans = \sum f[m][i][S]\)
这里把题面的l换成m了 表示密码长度
如果方案数小于等于42的话
说明这个密码是给定词拼成的 不会有自由字母
那么就逆向找到转移到它的状态 记录密码就好啦
注意比较那里原来写的是
if(x.s[i] > y.s[i]) return 1;
显然这样是不行的啊qvq
#include <cmath>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <complex>
#include <ctime>
#include <vector>
#include <queue>
#include <bitset>
#define mp(x, y) make_pair(x, y)
using namespace std;
const int N = 12;
const int M = 102;
const int Sig = 26;
int m, n, acsize, vsize, S;
int en[N], c[M], val[M];
long long ans, f[26][M][(1 << 10) + 5];
struct STR{
char s[30];
void print(){s[m + 1] = '\0'; printf("%s\n", s + 1);}
friend bool operator <(STR x, STR y){
for(int i = 1; i <= m; ++i)
if(x.s[i] != y.s[i]) return x.s[i] > y.s[i];
return 0;
}//大于
}stk;
vector<STR> str;
struct AC{
int ch[M][Sig], fail[M];
queue<int> que;
void ins(char* ss, int id){
int now = 0, len = strlen(ss + 1);
for(int i = 1, cc; i <= len; ++i){
cc = ss[i] - 'a';
if(!ch[now][cc]) ch[now][cc] = ++acsize;
now = ch[now][cc]; c[now] = cc;
}
en[id] = now, val[now] = 1;
}
void build(){
int now = 0;
for(int i = 0; i < Sig; ++i) if(ch[0][i]) que.push(ch[0][i]);
while(!que.empty()){
int fro = que.front(); que.pop();
for(int i = 0; i < Sig; ++i){
if(ch[fro][i]) fail[ch[fro][i]] = ch[fail[fro]][i], que.push(ch[fro][i]);//!!
else ch[fro][i] = ch[fail[fro]][i];
}
}
for(int i = 0; i <= acsize; ++i) val[fail[i]] = 0;
for(int i = 0; i <= acsize; ++i) if(val[i])
val[i] = (1 << vsize), ++vsize;
S = (1 << vsize) - 1;
}
void DP(){
f[0][0][0] = 1;
for(int i = 0; i < m; ++i)
for(int j = 0; j <= acsize; ++j)
for(int k = 0; k <= S; ++k) if(f[i][j][k]){
for(int t = 0; t < Sig; ++t){
f[i + 1][ch[j][t]][k | val[ch[j][t]]] += f[i][j][k];
// printf("%d %d %d %lld\n", i, j, k, f[i + 1][ch[j][t]][k | val[ch[j][t]]]);
}
}
}
}ac;
void dfs(int x, int cur, int y, int z){
stk.s[x] = z + 'a';
if(x == 1){str.push_back(stk); return ;}
for(int i = 0; i <= acsize; ++i)
if(f[x - 1][i][y] > 0 && ac.ch[i][z] == cur)
dfs(x - 1, i, y, c[i]);
if(val[cur])
for(int i = 0; i <= acsize; ++i)
if(f[x - 1][i][y ^ val[cur]] > 0 && ac.ch[i][z] == cur)
dfs(x - 1, i, y ^ val[cur], c[i]);
}
int main(){
scanf("%d%d", &m, &n);
char ss[N];
for(int i = 1; i <= n; ++i){
scanf("%s", ss + 1);
ac.ins(ss, i);
}
ac.build();
ac.DP();
for(int i = 0; i <= acsize; ++i)
ans += f[m][i][S];
printf("%lld\n", ans);
if(ans > 42) return 0;
for(int i = 0; i <= acsize; ++i)
if(f[m][i][S]) dfs(m, i, S, c[i]);
sort(str.begin(), str.end());
while(!str.empty()){
(str.back()).print(); str.pop_back();
}
return 0;
}