一、题目
二、解法
这道题必须要考虑到终止状态,由于题目给的是 串,所以最后的状态一定是前面都是 ,后面全是 。设 为 的个数, 表示前 个数中有 个数是 的概率,从 转移出去:
- 增加一个 ,从前面选一个 ,后面选一个 :
- 减少一个 ,从前面选一个 ,后面选一个 :
- 不增不减,只选前 后,选前后 :
很大,但我们可以做矩阵加速,注意设置矩阵的时候是从 转移到 ,所以要把上文的 替换成 ,具体可以参考代码。
#include <cstdio>
#include <cstring>
const int M = 105;
const int MOD = 1e9+7;
#define int long long
int read()
{
int x=0,f=1;char c;
while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
return x*f;
}
int n,m,k,t,t1,t2,a[M];
struct Matrix
{
int n,m,a[M][M];
Matrix() {n=m=0;memset(a,0,sizeof a);}
void clear() {memset(a,0,sizeof a);}
Matrix operator * (const Matrix &b) const
{
Matrix r;
r.n=n;r.m=b.m;
for(int i=0;i<=n;i++)
for(int j=0;j<=m;j++)
for(int k=0;k<=b.m;k++)
r.a[i][k]=(r.a[i][k]+a[i][j]*b.a[j][k])%MOD;
return r;
}
void print()
{
for(int i=1;i<=n;i++,puts(""))
for(int j=1;j<=m;j++)
printf("%lld ",a[i][j]);
}
}A,F;
Matrix qkpow(Matrix a,int b)
{
Matrix r;
r.n=r.m=a.n;
for(int i=1;i<=a.n;i++)
r.a[i][i]=1;
while(b>0)
{
if(b&1) r=r*a;
a=a*a;
b>>=1;
}
return r;
}
int fast(int a,int b)
{
int r=1;
while(b>0)
{
if(b&1) r=r*a%MOD;
a=a*a%MOD;
b>>=1;
}
return r;
}
signed main()
{
n=read();k=read();
for(int i=1;i<=n;i++)
{
a[i]=read();
if(!a[i]) m++;
}
for(int i=1;i<=m;i++)
if(!a[i]) t++;
A.n=A.m=F.n=m;F.m=1;
if(m==0 || m==n)
{
puts("1");
return 0;
}
t1=m*(m-1)/2;t2=(n-m)*(n-m-1)/2;
int inv=fast(n*(n-1)/2,MOD-2);
for(int i=0;i<=m;i++)
{
if(i>0) A.a[i][i-1]=(m-(i-1))*(m-(i-1));
A.a[i][i]=t1+t2+i*(m-i)+(m-i)*(n-2*m+i);
if(i<m) A.a[i][i+1]=(i+1)*(n-2*m+(i+1));
}
F.a[t][1]=1;
A=qkpow(A,k);F=A*F;
printf("%lld\n",F.a[m][1]*fast(inv,k)%MOD);
}