给你m个01串,问你有多少个长度为2L的01串,满足前半段倒置取反后等于后半段,并且包含所有的m个01串。
考虑单词完全在中线前面或者后面的情况,直接将单词及其倒置取反插入AC自动机,AC自动机每个结点用个tag压位记录单词集合。
对于跨越中线的情况,比如说110010是一个单词,枚举一个中线,
11 | 0010
在前面添加上10,变成10 11 | 0010,
那么其前半部分1011也是一个合法的单词,只不过这种类型的单词只有在dp到长度恰好为L时才能用。
于是AC自动机上每个结点记录两种tag,tag1是原始的单词集合(还有将它倒置再取反的单词),tag2是跨越中线的单词。
f(i,j,S)表示长度为i,到第j个结点,当前集合为S的方案数。第一维滚动。i枚举到n-1时,要用tag2,否则只用tag1。
#include#include #include #include #include #include using namespace std;queue q;#define MOD 998244353int child[2645][2],fail[2645],size,f[2][2645][64],tag[2645],tag2[2645];void Insert(string S,int id){ int len=S.length(); int now=0; for(int i=0;i >s; int len=s.length();// cout<<"::"< <=0;++k,--l){ if((s[k]-'0')^(s[l]-'0')!=1){ flag=0; break; } } if(!flag){ continue; } t=s.substr(0,j+1); for(int k=(j+1)*2;k