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.
A 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 .
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.
A 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(1≤t≤5)
, the number of the testcases.
For each testcase, the first line contains two numbers n,L(1≤n≤6,1≤L≤100) .
Then n lines follow, each line contains a 01 string si(1≤|si|≤20) .
For each testcase, the first line contains two numbers n,L(1≤n≤6,1≤L≤100) .
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
2 2 2 011 001 2 3 011 001
Sample Output
1 4
Source
Recommend
思路:这题好恶心。。。调了大半天才调出来。很明显是ac自动机+dp。我们可以这么想,我们构造一个L的串,然后把他反对称就好了。那么前面包含的串它的反对称串也必定包含。所以构造ac自动机的时候把这n个串和他们的反对称串都插进去然后结尾标记为同一个状态。还有一个情况就是串出现的地方跨过了中间。例如样例中的011和001,若00出现在我们构造的串的最后,那么根据反对称中间会出现0011,也就是包含了011和001,所以我们把串拆开。把出现在结尾也可改变状态的串插入自动机。可能说明有点复杂,具体描述看官方博客的题解吧。下面给代码:
#include <bits/stdc++.h>
using namespace std;
#define maxn 5005
const 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);
}
}