CF1151F Sonya and Informatics

一、题目

点此看题

二、解法

这道题必须要考虑到终止状态,由于题目给的是 0 / 1 0/1 串,所以最后的状态一定是前面都是 0 0 ,后面全是 1 1 。设 m m 0 0 的个数, d p [ i ] dp[i] 表示前 m m 个数中有 i i 个数是 0 0 的概率,从 d p [ i ] dp[i] 转移出去:

  • 增加一个 0 0 ,从前面选一个 1 1 ,后面选一个 0 0 d p [ i ] × ( m i ) 2 dp[i]\times(m-i)^2
  • 减少一个 0 0 ,从前面选一个 0 0 ,后面选一个 1 1 d p [ i ] × i × ( n 2 m + i ) dp[i]\times i\times(n-2m+i)
  • 不增不减,只选前 / / 后,选前后 1 / 0 1/0 C ( m , 2 ) + C ( n m , 2 ) + i ( m i ) + ( m i ) ( n 2 m + i ) C(m,2)+C(n-m,2)+i(m-i)+(m-i)(n-2m+i)

k k 很大,但我们可以做矩阵加速,注意设置矩阵的时候是从 i + 1 / i 1 i+1/i-1 转移到 i i ,所以要把上文的 i i 替换成 i + 1 / i 1 i+1/i-1 ,具体可以参考代码。

#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);
}

猜你喜欢

转载自blog.csdn.net/C202044zxy/article/details/107919777