解法:我们先把母串和所有与其只有一个字符不同的01串插入字典树,建立AC自动机,预处理从
u
u
u节点出发,有
d
[
u
]
d[u]
d[u]条长度为n的路径刚好走完才走到叶子节点,然后我们枚举母串与T近似匹配的位置,假设匹配完后缀长度为
l
e
n
len
len,前缀长度为
N
N
N,那我们可以从根节点开始走所有路径,走N次(不能走到叶子节点),定义走完N次后走到
u
u
u节点的次数为
d
p
[
N
]
[
u
]
dp[N][u]
dp[N][u],那么
a
n
s
+
=
d
p
[
N
]
[
u
]
∗
d
[
u
]
∗
2
l
e
n
ans += dp[N][u]*d[u]*2^{len}
ans+=dp[N][u]∗d[u]∗2len,
d
p
dp
dp的转移:找到
u
u
u的儿子
s
o
n
son
son(没有儿子沿着
f
a
i
l
fail
fail指针去找儿子),如果
s
o
n
son
son不为叶子,那么
d
p
[
N
+
1
]
[
s
o
n
]
+
=
d
p
[
N
]
[
u
]
dp[N+1][son]+=dp[N][u]
dp[N+1][son]+=dp[N][u]
#include<bits/stdc++.h>#define ll long long
using namespace std;constint maxn =40*41;int ch[maxn][2], f[maxn], sz, leaf[maxn], n;
ll d[maxn], P[41], dp[2][maxn];char s[41];voidinit(){for(int i =0; i <= sz; i++){
f[i]= d[i]= leaf[i]=0;memset(ch[i],0,sizeof(ch[i]));}
sz =0;}voidinsert(char*S){int o =0;for(int i =1; i <= n; i++){int c = S[i]-'0';if(!ch[o][c])
ch[o][c]=++sz;
o = ch[o][c];}
leaf[o]=1;}voidbuild(){int o =0;
queue<int> q;for(int i =0; i <2; i++)if(ch[o][i])
q.push(ch[o][i]);while(!q.empty()){
o = q.front();
q.pop();for(int i =0; i <2; i++)if(ch[o][i]){int v = ch[o][i];
f[v]= ch[f[o]][i];
q.push(v);}else
ch[o][i]= ch[f[o]][i];}}intfind(int o,int p){if(leaf[o]&& p != n +1)return0;if(p == n +1)return1;int c = s[p]-'0';returnfind(ch[o][c], p +1);}voidclear(int cur){for(int i =0; i <= sz; i++)
dp[cur][i]=0;}
ll solve(){int m;scanf("%d%d%s",&n,&m, s +1);init();insert(s);for(int i =1; i <= n; i++){
s[i]=1^(s[i]-'0')+'0';insert(s);
s[i]=1^(s[i]-'0')+'0';}build();
d[0]= n +1;for(int i =1; i <= sz; i++){
d[i]+=find(i,1);for(int j =1; j <= n; j++){
s[j]=1^(s[j]-'0')+'0';
d[i]+=find(i,1);
s[j]=1^(s[j]-'0')+'0';}}
ll ans = d[0]* P[m - n];clear(1);
dp[1][0]=1;for(int i =1, cur =0; i <= m - n; i++, cur ^=1){clear(cur);for(int j =0; j <= sz; j++)for(int k =0; k <2; k++){int v = ch[j][k];if(leaf[v])continue;
ans += dp[!cur][j]* d[v]* P[m - n - i];
dp[cur][v]+= dp[!cur][j];}}return ans;}intmain(){int T;
P[0]=1;for(int i =1; i <41; i++)
P[i]= P[i -1]*2;scanf("%d",&T);while(T--)printf("%lld\n",solve());}