HDU 6086 Rikka with String

Rikka with String

http://acm.hdu.edu.cn/showproblem.php?pid=6086

题意:

  求一个长度为2L的,包含所给定的n的串,并且满足非对称。

分析:

  AC自动机+状压dp。

  首先给这个n个串,建立AC自动机。然后去枚举长度为L的一个串,就可以知道另一半了。

  如果给定的串完全存在于左边或者右边,那么直接往AC自动机加入这个串或者取反后的反串。如果是跨越中间,那么暴力的把所有的串,从中间切开,然后判断是否合法,加入到AC自动机上就行,如果长度枚举到了i-1的时候,这些串的状态才有用。

代码:

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<cmath>
  6 #include<cctype>
  7 #include<set>
  8 #include<queue>
  9 #include<vector>
 10 #include<map>
 11 using namespace std;
 12 typedef long long LL;
 13 
 14 inline int read() {
 15     int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
 16     for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
 17 }
 18 
 19 const int mod = 998244353;
 20 int ch[2500][2], sta1[2500], sta2[2500], fail[2500], q[2500], dp[2][2500][70];
 21 int Index;
 22 char s[100], t[100], a[100], b[100];
 23 
 24 void Insert(char *s,int n,int id,bool f) {
 25     int u = 0;
 26     for (int i = 0; i < n; ++i) {
 27         int c = s[i] - '0';
 28         if (!ch[u][c]) ch[u][c] = ++Index;
 29         u = ch[u][c];
 30     }
 31     if (f) sta1[u] |= (1 << id);
 32     else sta2[u] |= (1 << id);
 33 }
 34 void build() {
 35     int L = 1, R = 0;
 36     for (int i = 0; i < 2; ++i) if (ch[0][i]) q[++R] = ch[0][i];
 37     while (L <= R) {
 38         int u = q[L ++];
 39         for (int c = 0; c < 2; ++c) {
 40             int v = ch[u][c];
 41             if (!v) { ch[u][c] = ch[fail[u]][c]; continue; }
 42             int p = fail[u]; while (p && !ch[p][c]) p = fail[p];
 43             q[++R] = v;
 44             fail[v] = ch[p][c];
 45             sta1[v] |= sta1[fail[v]], sta2[v] |= sta2[fail[v]];
 46         }
 47     }
 48 }
 49 void update(char *s,int n,int id) {
 50     int c1 = 0, c2 = 0, f = 0;
 51     for (int i = 0; i < n - 1; ++i) {
 52         c1 = c2 = f = 0;
 53         for (int j = i; j >= 0; --j) a[c1 ++] = s[j];a[c1] = '\0';
 54         for (int j = i + 1; j < n; ++j) b[c2 ++] = s[j]; b[c2] = '\0';
 55         for (int j = 0; j < c1 && j < c2; ++j) if (a[j] == b[j]) { f = 1; break; }
 56         if (f) continue;
 57         for (int j = c1; j < c2; ++j) a[j] = b[j] == '0' ? '1' : '0';
 58         reverse(a, a + max(c1, c2));
 59         Insert(a, max(c1, c2), id, 0); // 长度为max(c1,c2)!!! 
 60     }
 61 }
 62 void init() {
 63     memset(dp, 0, sizeof(dp));
 64     memset(ch, 0, sizeof(ch));
 65     memset(fail, 0, sizeof(fail));
 66     memset(sta1, 0, sizeof(sta1));
 67     memset(sta2, 0, sizeof(sta2));
 68 }
 69 inline void add(int &x,int y) { x += y; if (x >= mod) x -= mod; }
 70 void solve() {
 71     init();
 72     int n = read(), L = read(), len;
 73     for (int i = 0; i < n; ++i) {
 74         scanf("%s", s); len = strlen(s);
 75         Insert(s, len, i, 1);
 76         for (int j = 0; j < len; ++j) t[j] = s[j]; 
 77         reverse(t, t + len);
 78         for (int j = 0; j < len; ++j) t[j] = t[j] == '0' ? '1' : '0';
 79         Insert(t, len, i, 1);
 80         update(s, len, i);
 81     }
 82     build();
 83     dp[0][0][0] = 1;
 84     int All = (1 << n) - 1, now = 0;
 85     for (int i = 0; i < L; ++i, now ^= 1) 
 86         for (int j = 0; j <= Index; ++j) 
 87             for (int s = 0; s <= All; ++s) {
 88                 if (dp[now][j][s] <= 0) continue;
 89                 for (int c = 0; c < 2; ++c) {
 90                     int nv = ch[j][c], ns = s | sta1[nv];
 91                     if (i == L - 1) ns |= sta2[nv];
 92                     add(dp[now ^ 1][nv][ns], dp[now][j][s]);
 93                 }
 94                 dp[now][j][s] = 0;
 95             }
 96     int ans = 0;
 97     for (int i = 0; i <= Index; ++i) add(ans, dp[now][i][All]);
 98     printf("%d\n",ans % mod);
 99 }
100 int main() { 
101     for (int T = read(); T --; ) solve();
102     return 0;
103 }

 

posted @ 2018-12-09 14:05  MJT12044  阅读(162)  评论(0编辑  收藏  举报