推公式辣鸡,和队友一起写了3小时= =。这张纸被用来垫烧烤盒了,最后是O(nk)的,不过网上别人的写法好像更加方便一点
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=5e4+5,maxm=100+5,mod=1e9+7;
char ss[maxn];
int a[maxn],sum[maxn];
LL ans[maxn];
LL T[maxm][maxn];// k n
LL s[maxn][maxm],num[maxn][maxm],inv[maxn][maxm],C[maxm][maxm];
int n,k;
inline long long qp(long long a,long long b)
{
long long ans=1,cnt=a;
while(b)
{
if(b&1)
ans=(ans*cnt)%mod;
cnt=(cnt*cnt)%mod;
b>>=1;
}
return ans;
}
int main() {
C[0][0]=1;
for(int i=1;i<maxm;++i){
C[i][0]=1;
for(int j=1;j<=maxm;++j)
C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
}
int _;
scanf("%d",&_);
while(_--)
{
scanf("%d%d",&n,&k);
scanf("%s",ss+1);
for(register int i=1;i<=n;++i)
a[i]=ss[i]-'0';
for(int i=1;i<=n;i++)
{
sum[i]=sum[i-1]+a[i];
//last[i]=pre[sum[i]];
//pre[sum[i]]=i;
}
for(register int i=0;i<=n;++i)
{
s[i][0]=1;
for(register int j=1;j<=k;++j){
s[i][j]=1ll*s[i][j-1]*sum[i]%mod;
}
if(sum[i]){
inv[i][k]=qp(s[i][k],mod-2);
for(int j=k-1;j>=0;j--)
inv[i][j]=inv[i][j+1]*sum[i]%mod;
}else{
for(int j=0;j<=k;j++)
inv[i][j]=1;
}
}
LL sgn=1;
if(k&1)sgn=-1;
for(int i=1;i<=n;i++){
T[0][i]=(T[0][i-1]+(1ll*mod+sgn*s[i-1][k])%mod)%mod;
}
for(int r=1;r<=k;r++)
{
int last=0;
for(int i=1;i<=n;i++){
LL sgn=1;
if((k-r)&1)sgn=-1;
if(sum[i-1]==0){
T[r][i]=(T[r][last]+s[i][r]*(1ll*mod+sgn*s[i-1][k-r])%mod)%mod;
continue;
}
last=i;
T[r][i]=(T[r][i-1]*inv[i-1][r]%mod*s[i][r]%mod
+s[i][r]*(1ll*mod+sgn*s[i-1][k-r])%mod)%mod;
}
}
for(int i=1;i<=n;i++)
ans[i]=0;
for(int i=1;i<=n;i++)
for(int r=0;r<=k;r++)
ans[i]=(ans[i]+C[k][r]*T[r][i])%mod;
for(int i=1;i<=n;++i)printf("%lld%c",ans[i],i==n?'\n':' ');
}
return 0;
}