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自动机,实现的同样是单文本串对多模式串的匹配。

  1 #include <algorithm>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <string>
  5 #include <queue>
  6 #include <map>
  7 #include <set>
  8 #include <ctime>
  9 #include <cmath>
 10 #include <iostream>
 11 #include <assert.h>
 12 #define pi acos(-1.)
 13 using namespace std;
 14 typedef long long ll;
 15 const int int_inf = 0x3f3f3f3f;
 16 const ll ll_inf = 1ll << 62;
 17 const int INT_INF = (int)((1ll << 31) - 1);
 18 const int mod = 1e6 + 7;
 19 const double double_inf = 1e30;
 20 typedef unsigned long long ul;
 21 #pragma comment(linker, "/STACK:102400000,102400000")
 22 #define max(a, b) ((a) > (b) ? (a) : (b))
 23 #define min(a, b) ((a) < (b) ? (a) : (b))
 24 #define mp make_pair
 25 #define st first
 26 #define nd second
 27 #define keyn (root->ch[1]->ch[0])
 28 #define lson (u << 1)
 29 #define rson (u << 1 | 1)
 30 #define pii pair<int, int>
 31 #define pll pair<ll, ll>
 32 #define pb push_back
 33 #define type(x) __typeof(x.begin())
 34 #define foreach(i, j) for(type(j)i = j.begin(); i != j.end(); i++)
 35 #define FOR(i, s, t) for(int i = (s); i <= (t); i++)
 36 #define ROF(i, t, s) for(int i = (t); i >= (s); i--)
 37 #define dbg(x) cout << x << endl
 38 #define dbg2(x, y) cout << x << " " << y << endl
 39 #define clr(x, i) memset(x, (i), sizeof(x))
 40 #define maximize(x, y) x = max((x), (y))
 41 #define minimize(x, y) x = min((x), (y))
 42 #define low_bit(x) ((x) & (-x))
 43 
 44 inline int readint(){
 45     int x;
 46     scanf("%d", &x);
 47     return x;
 48 }
 49 
 50 inline int readstr(char *s){
 51     scanf("%s", s);
 52     return strlen(s);
 53 }
 54 
 55 class cmpt{
 56 public:
 57     bool operator () (const int &x, const int &y) const{
 58         return x > y;
 59     }
 60 };
 61 
 62 int Rand(int x, int o){
 63     //if o set, return [1, x], else return [0, x - 1]
 64     if(!x) return 0;
 65     int tem = (int)((double)rand() / RAND_MAX * x) % x;
 66     return o ? tem + 1 : tem;
 67 }
 68 
 69 void data_gen(){
 70     srand(time(0));
 71     freopen("in.txt", "w", stdout);
 72     int times = 10;
 73     printf("%d\n", times);
 74     while(times--){
 75         int n = Rand(500, 1), m = Rand(500, 1);
 76         printf("%d %d\n", n, m);
 77         FOR(i, 1, n){
 78             FOR(j, 1, m) printf("%c", Rand(2, 0) + 'a');
 79             putchar('\n');
 80         }
 81         n = Rand(min(10, n), 1), m = Rand(min(10, m), 1);
 82         printf("%d %d\n", n, m);
 83         FOR(i, 1, n){
 84             FOR(j, 1, m) printf("%c", Rand(2, 0) + 'a');
 85             putchar('\n');
 86         }
 87     }
 88 }
 89 
 90 struct cmpx{
 91     bool operator () (int x, int y) { return x > y; }
 92 };
 93 int debug = 0;
 94 int dx[] = {-1, 1, 0, 0};
 95 int dy[] = {0, 0, -1, 1};
 96 //-------------------------------------------------------------------------
 97 const int maxn = 12;
 98 const int sigma_size = 26;
 99 ll dp[30][1 << 12][maxn * maxn];
100 int nex[maxn * maxn][sigma_size];
101 int state[maxn * maxn];
102 int info[maxn * maxn];
103 int tot;
104 map<string, int> mapi;
105 struct Trie{
106     int ch[maxn * maxn][sigma_size];
107     int idx(char c) { return c - 'a'; }
108     int sz;
109     void init() { clr(ch[0], 0); sz = 0; clr(info, 0); }
110     void insert(char *s){
111         int u = 0;
112         while(*s){
113             int v = ch[u][idx(*s)];
114             if(!v) { ch[u][idx(*s)] = v = ++sz; clr(ch[sz], 0); }
115             u = v;
116             ++s;
117         }
118         if(!info[u]) info[u] = ++tot;
119     }
120 
121     char tem[20];
122     int k;
123 
124     void dfs1(int u){
125         FOR(i, 0, sigma_size - 1){
126             int v = ch[u][i];
127             if(!v) continue;
128             tem[k++] = i + 'a', tem[k] = '\0';
129             mapi[string(tem)] = v;
130             dfs1(v);
131             --k;
132         }
133     }
134 
135     void dfs2(int u){
136         FOR(i, 0, sigma_size - 1){
137             int v = ch[u][i];
138             if(!v) continue;
139             tem[k++] = i + 'a', tem[k] = '\0';
140             FOR(j, 0, k - 1){
141                 string str = string(tem + j);
142                 if(mapi.find(str) != mapi.end() && info[mapi[str]]) state[v] |= 1 << (info[mapi[str]] - 1);
143             }
144             FOR(j, 0, sigma_size - 1){
145                 tem[k++] = j + 'a', tem[k] = '\0';
146                 int ok = 0;
147                 FOR(z, 0, k - 1){
148                     string str = string(tem + z);
149                     if(mapi.find(str) != mapi.end()){
150                         nex[v][j] = mapi[str];
151                         ok = 1;
152                         break;
153                     }
154                 }
155                 if(!ok) nex[v][j] = 0;
156                 --k;
157             }
158             dfs2(v);
159             --k;
160         }
161     }
162     int S;
163     void getNext(){
164         mapi.clear();
165         k = 0, dfs1(0);
166         k = 0, clr(state, 0), dfs2(0);
167         FOR(i, 0, sigma_size - 1) nex[0][i] = ch[0][i];
168     }
169 }trie;
170 
171 ll power(ll a, ll p){
172     ll ans = 1;
173     while(p){
174         if(p & 1) ans *= a;
175         p >>= 1ll;
176         a = a * a;
177     }
178     return ans;
179 }
180 int n, m;
181 char mt[maxn][maxn];
182 
183 ll dfs(int u, int S, int l){
184     if(dp[u][S][l] != -1) return dp[u][S][l];
185     if(u == n) return dp[u][S][l] = S == ((1 << tot) - 1);
186     if(S == (1 << tot) - 1) return dp[u][S][l] = power(26, n - u);
187     ll tem = 0;
188     FOR(i, 0, sigma_size - 1){
189         int next_pointer = nex[l][i];
190         int next_S = S | state[next_pointer];
191         tem += dfs(u + 1, next_S, next_pointer);
192     }
193     return dp[u][S][l] = tem;
194 }
195 
196 char buf[maxn << 2];
197 int k;
198 
199 void printAns(int u, int S, int l){
200     if(!dp[u][S][l]) return;
201     if(u == n){
202         buf[k] = '\0';
203         puts(buf);
204         return;
205     }
206     FOR(i, 0, sigma_size - 1){
207         int next_pointer = nex[l][i];
208         int next_S = S | state[next_pointer];
209         buf[k++] = i + 'a';
210         printAns(u + 1, next_S, next_pointer);
211         --k;
212     }
213 }
214 //-------------------------------------------------------------------------
215 
216 int main(){
217     //data_gen(); return 0;
218     //C(); return 0;
219     debug = 0;
220     ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
221     if(debug) freopen("in.txt", "r", stdin);
222     //freopen("out.txt", "w", stdout);
223     int kase = 0;
224     while(~scanf("%d%d", &n, &m) && n){
225         FOR(i, 0, m - 1) scanf("%s", mt[i]);
226         trie.init(), tot = 0;
227         FOR(i, 0, m - 1) trie.insert(mt[i]);
228         trie.getNext();
229         clr(dp, -1);
230         ll ans = dfs(0, 0, 0);
231         printf("Case %d: %lld suspects\n", ++kase, ans);
232         if(ans <= 42) k = 0, printAns(0, 0, 0);
233     }
234     //////////////////////////////////////////////////////////////////////////////////////////////////////////////
235     return 0;
236 }
code:

 

posted @ 2016-07-21 02:44  astoninfer  阅读(624)  评论(0编辑  收藏  举报