首先考虑如果要完成指定
k
个课程,那么期望应该是
令
ft
表示
t
时刻之前 要求未被完成的概率
令
然后瘦腿一发
E======∑t=0∞ft∑t=0∞∑S(−1)|S|(1−pS,t)∑t=0∞−∑S(−1)|S|pS,t−∑S(−1)|S|∑t=0∞pS,t−∑S(−1)|S|E(S)−∑S(−1)|S|Fk(S)
这样复杂度是
2n−m+1
乘上一些
nm
什么的什么我忘了
可以解决
n−m
较小的情况
然后剩下的情况 我们直接计算
Fk
的贡献
令
dpi,s,k
表示做到第
i
个,第 i 个需要学会集合
这样复杂度是
2m
乘上一些
nm
什么的什么我忘了
然后就可以了
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#define cl(x) memset(x,0,sizeof(x))
using namespace std;
typedef long long ll;
#define read(x) scanf("%d",&(x))
const int P=998244353;
const int N=32;
inline ll Pow(ll a,int b){
ll ret=1; for (;b;b>>=1,a=a*a%P) if (b&1) ret=ret*a%P; return ret;
}
ll inv[1005];
inline void Pre(){
inv[1]=1; for (int i=2;i<=1000;i++) inv[i]=(ll)(P-P/i)*inv[P%i]%P;
}
inline ll Inv(ll a){
//return Pow(a,P-2);
return inv[a];
}
int n,m,tot;
char t[N][N]; int len[N];
char s[N];
inline bool check(){
for (int i=1;i<=n-m+1;i++){
int flag=0;
for (int j=i;j<=i+m-1;j++)
for (int k=1;k<=len[j];k++)
if (t[j][k]==s[j-i+1])
flag++;
if (flag==m) return 1;
}
return 0;
}
ll F[N*N];
bool b[N][26],a[N][26];
int tmp[N],pnt;
int g[N];
int tag[N];
inline void Solve1(){
ll ans=0;
pnt=0;
for (int i=1;i<=n;i++) if (tag[i]) tmp[++pnt]=i;
for (int x=0;x<(1<<pnt);x++){
cl(a); int c=0,k=0;
for (int i=1;i<=pnt;i++)
if (x>>(i-1)&1){
int p=tmp[i];
for (int j=p;j<=p+m-1;j++){
k+=a[j][s[j-p+1]-'a']==0;
a[j][s[j-p+1]-'a']=1;
}
c++;
}
if (c&1)
ans+=P-F[k];
else
ans+=F[k];
}
ans=(P-ans%P)%P;
printf("%lld\n",ans);
}
int f[2][1<<15][1005];
int cnt[1<<15];
int vst[26],clk;
int tim;
inline void Solve2(){
for (int i=1;i<=n;i++) len[i]+=len[i-1];
for (int j=0;j<(1<<m);j++){
++clk; int c=0;
for (int i=0;i<m;i++)
if (j>>i&1)
if (vst[s[i+1]-'a']!=clk)
c++,vst[s[i+1]-'a']=clk;
cnt[j]=c;
}
int t=0;
f[t][0][0]=1;
for (int i=0;i<n;i++,t^=1)
for (int j=0;j<(1<<m);j++)
for (int k=0;k<=len[i];k++)
if (f[t][j][k]){
++tim;
int s=(j<<1)&((1<<m)-1);
if (tag[i+1])
(f[t^1][s|1][k+cnt[s|1]]+=P-f[t][j][k])%=P;
(f[t^1][s][k+cnt[s]]+=f[t][j][k])%=P;
f[t][j][k]=0;
}
ll ans=0;
for (int k=0;k<=len[n];k++){
ll c=0;
for (int j=0;j<(1<<m);j++)
if (f[t][j][k])
c+=f[t][j][k],f[t][j][k]=0;
ans+=F[k]*(c%P)%P;
}
ans=(P-ans%P)%P;
printf("%lld\n",ans);
}
int main(){
int T;
freopen("t.in","r",stdin);
freopen("t.out","w",stdout);
read(T); Pre();
while (T--){
// tim=0;
read(n); read(m); tot=0; cl(b);
for (int i=1;i<=n;i++) scanf("%s",t[i]+1),len[i]=strlen(t[i]+1),tot+=len[i];
scanf("%s",s+1);
for (int i=1;i<=n;i++) for (int j=1;j<=len[i];j++) b[i][t[i][j]-'a']=1;
cl(g);
for (int i=1;i<=n;i++)
for (int j=0;j<m;j++)
if (b[i][s[j+1]-'a'])
g[i]+=1<<j;
cl(tag);
for (int i=1;i<=n-m+1;i++){
tag[i]=1;
for (int j=1;j<=m;j++)
tag[i]&=(g[i+j-1]>>(j-1)&1);
}
for (int k=0;k<=tot;k++){
F[k]=0;
for (int i=0;i<k;i++)
F[k]+=(ll)tot*Inv(k-i)%P;
F[k]%=P;
}
if (!check()) { printf("-1\n"); continue; }
if (n-m+1<=17)
Solve1();
else
Solve2();
// fprintf(stderr,"%d\n",tim);
}
return 0;
}