题意:
给你一串值包含1和0的数字,现在有一种操作:等概率的交换这个数组中任意两个位置的数,这两个位置不重复,问你经过k次这种操作之后这串数是非递减的概率是多少。
题解:
他这个k很大有1e9,所以肯定不是普通的dp,但是可以用dp方程写出来:假设我们开的下k这个数,假设总共有sumz个0,那我们用dp[i][j]表示到第i步的时候前面sumz个数中有j个0,那么dp方程就是dp[i][j]=dp[i-1][j-1]*(?)+dp[i-1][j]*(?)+dp[i-1][j+1]*(?)这种形式。但是开不下,而且我们又把方程写出来了,所以剩下一种可能就是矩阵快速幂。按照刚才的思路,前面sumz个位置中有j个0可以从j-1,j,j+1个0转移过来,那么就可以得出以下矩阵:
首先我们是枚举0的个数,设它为i,那么0在numz之前的有i个,0在numz之后的有numz-i个,
1在numz之前的有numz-i个,1在numz之后的有n-numz-numz-i个。
那么+1的情况就是(numz-i)*(numz-i)
-1的情况就是i*(n-2*numz+i)
不增不减就是剩下的数。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=101;
const ll mod=1e9+7;
struct Matrix
{
ll m[N][N];
Matrix()
{
memset(m,0,sizeof(m));
}
Matrix operator *(const Matrix &b)const
{
Matrix c;
for(int i=0; i<N; i++)
{
for(int j=0; j<N; j++)
{
for(int k=0; k<N; k++)
{
c.m[i][j]=(c.m[i][j]+(m[i][k]*b.m[k][j])%mod)%mod;
}
}
}
return c;
}
}m;
int a[N];
ll qpow(ll a,ll b)
{
ll ans=1,ret=a;
while(b)
{
if(b&1)
ans=ans*ret%mod;
ret=ret*ret%mod;
b>>=1;
}
return ans;
}
int main()
{
int n,k,numz=0,atz=0;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),numz+=a[i]==0;
for(int i=1;i<=numz;i++)
atz+=a[i]==0;
Matrix ans;
ans.m[0][atz]=1;
for(int i=0;i<=numz;i++)
{
ll add=(numz-i)*(numz-i);
ll dec=i*(n-2*numz+i);
m.m[i][i]=(n-1)*n/2-add-dec;
if(i)
m.m[i][i-1]=dec;
if(i<numz)
m.m[i][i+1]=add;
}
ll inv=qpow(qpow((n-1)*n/2,k),mod-2);
while(k)
{
if(k&1)
ans=ans*m;
m=m*m;
k>>=1;
}
return 0*printf("%lld\n",ans.m[0][numz]*inv%mod);
}