hdu 6086 Rikka with String ac自动机+dp

来源:互联网 发布:2017欧文季后赛数据 编辑:程序博客网 时间:2024/05/21 07:32


Rikka with String

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 210    Accepted Submission(s): 58


Problem Description
As we know, Rikka is poor at math. Yuta is worrying about this situation, so he gives Rikka some math tasks to practice. There is one of them:

Yuta has n 01 strings si, and he wants to know the number of 01 antisymmetric strings of length 2L which contain all given strings si as continuous substrings.

01 string s is antisymmetric if and only if s[i]s[|s|i+1] for all i[1,|s|].

It is too difficult for Rikka. Can you help her?

In the second sample, the strings which satisfy all the restrictions are 000111,001011,011001,100110.
 

Input
The first line contains a number t(1t5), the number of the testcases. 

For each testcase, the first line contains two numbers n,L(1n6,1L100)

Then n lines follow, each line contains a 01 string si(1|si|20).
 

Output
For each testcase, print a single line with a single number -- the answer modulo 998244353.
 

Sample Input
22 20110012 3011001
 

Sample Output
14
 

Source
2017 Multi-University Training Contest - Team 5
 

Recommend
liuyiding   |   We have carefully selected several similar problems for you:  6095 6094 6093 6092 6091 
 

Statistic | Submit | Discuss | Note
题意:给你n个串,长度L,问你能构造出多少个字符串长度为2L满足包含这n个串以及他的反对称串。

思路:这题好恶心。。。调了大半天才调出来。很明显是ac自动机+dp。我们可以这么想,我们构造一个L的串,然后把他反对称就好了。那么前面包含的串它的反对称串也必定包含。所以构造ac自动机的时候把这n个串和他们的反对称串都插进去然后结尾标记为同一个状态。还有一个情况就是串出现的地方跨过了中间。例如样例中的011和001,若00出现在我们构造的串的最后,那么根据反对称中间会出现0011,也就是包含了011和001,所以我们把串拆开。把出现在结尾也可改变状态的串插入自动机。可能说明有点复杂,具体描述看官方博客的题解吧。下面给代码:

#include <bits/stdc++.h>using namespace std;#define maxn 5005const int mod = 998244353;struct Trie{int next[maxn][2], fail[maxn], end1[maxn], end2[maxn], mark[maxn];int root, L;int newnode(){for (int i = 0; i<2; i++)next[L][i] = -1;end1[L] = 0;end2[L++] = 0;return L - 1;}void init(){memset(mark, -1, sizeof(mark));L  = 0;root = newnode();}void insert1(char buf[],int &id){int len = strlen(buf);int now = root;for (int i = 0; i<len; i++){if (next[now][buf[i] - '0'] == -1)next[now][buf[i] - '0'] = newnode();now = next[now][buf[i] - '0'];}if (mark[now]>=0){id=mark[now];return;}mark[now] = id;end1[now] |= 1 << mark[now];}void insert2(char buf[],int &id){int len = strlen(buf);int now = root;for (int i = 0; i<len; i++){if (next[now][buf[i] - '0'] == -1)next[now][buf[i] - '0'] = newnode();now = next[now][buf[i] - '0'];}end2[now] |= 1 << id;}void build(){queue<int>Q;fail[root] = root;for (int i = 0; i<2; i++){if (next[root][i] == -1)next[root][i] = root;else{fail[next[root][i]] = root;Q.push(next[root][i]);}}while (!Q.empty()){int now = Q.front();Q.pop();end1[now] |= end1[fail[now]];end2[now] |= end2[fail[now]];for (int i = 0; i<2; i++){if (next[now][i] == -1)next[now][i] = next[fail[now]][i];else{fail[next[now][i]] = next[fail[now]][i];Q.push(next[now][i]);}}}}};Trie ac;const int maxlen=100;void getsub(char *s,int id){int len=strlen(s);char ss[maxlen];strcpy(ss,s);ss[len]='\0';for(int i=1;i<len;i++){int length=len-i+1;bool flag=true;bool leftover=false;bool rightover=false;for(int j=1;j<=length;j++){if(i-j<0) {leftover=true;break;}if(ss[i+j-1]==ss[i-j]) {flag=false;break;}}if(flag){char str[25];int now=0;if(leftover){for(int j=len-1;j>=i;j--) str[now++]=!(ss[j]-'0')+'0';}else{for(int j=0;j<i;j++) str[now++]=(ss[j]-'0')+'0';}str[now]='\0';ac.insert2(str,id);}}}int dp[2][maxn][(1 << 6) + 5];int main(){int t;scanf("%d", &t);char buf[10][25];char s[25];while (t--){memset(dp, 0, sizeof(dp));int n, l;ac.init();int id=0;scanf("%d%d", &n, &l);for (int i = 0; i < n; i++){scanf("%s", buf[i]);int now=id;ac.insert1(buf[i],now);getsub(buf[i],now);strcpy(s,buf[i]);strrev(s);for(int j=0;s[j]!='\0';j++)s[j]=(!(s[j]-'0'))+'0';ac.insert1(s,now);if(now==id)id++;}ac.build();dp[0][0][0] = 1;int now=0;for (int i = 1; i <= l; i++){now^=1;memset(dp[now],0,sizeof(dp[now]));for (int j = 0; j < ac.L; j++)for (int k = 0; k < 1 << id; k++)for (int ll = 0; ll < 2; ll++){int Next = ac.next[j][ll];int nextstatus = k | ac.end1[Next];if (i == l)nextstatus |= ac.end2[Next];dp[now][Next][nextstatus] += dp[now^1][j][k];dp[now][Next][nextstatus] %= mod;}}int ans = 0;for (int i = 0; i < ac.L; i++){ans += dp[now][i][(1 << id) - 1];ans %= mod;}printf("%d\n", ans);}}