[CF1151F]Sonya and Informatics

做题时间:2022.10.12

给定一个长度为 n(n100) 的01串,进行 k(k109) 次操作,每次操作等概率选择两个位置 i,j(1i<jn),交换 i,j 位置上的数。求 k 次操作后,该01串变成不降序列的概率,答案对 109+7 取模

第一行两个整数 n,k

第二行 n 个整数表示01串

一行一个整数表示概率 mod109+7

计数dp、矩阵快速幂

发现0和1的数量保持不变。假设串中有 m 个0,那么最终的序列会变成连续 m 个0和连续 nm 个1拼成的串。发现前 m 个数中0的个数会有影响,于是设 fi,j 表示第 i 次操作后前 m 个数中有 j 个0的方案数,考虑第 i 次操作将前 m 个数中0的个数+1/不变/-1:

  1. +1则是选择前 m 个数中的1,共 m(j1) 个,以及后 nm 个数中的0,共 m(j1) 个,总共 (mj+1)2 种选法,设他为 Aj,因此方案数为 fi,j1×Aj
  2. 不变则是在前 m 个数或后 nm 个数之间任意对调,或将前面的0/1与后面对应的0/1对调,共 (2m)+(2nm)+(mj)(n2m+j)+j(mj) 种,设他为 Bj ,则方案数为 fi,j×Bj
  3. -1则是选择前 m 个数中的0,共 j+1 种选择,以及后 nm 个数中的1,共 n2m+j+1 种选择,总共 (j+1)(n2m+j+1) 种选法,设他为 Cj,则方案数为 fi,j+1×Cj

也就是: fi,j=fi,j1×Aj+fi,j×Bj+fi,j+1×Cj

t 表示前 m 个数种0的个数,初始化即为 f0,t=1

然后发现第一维很大,第二维很小,所以可以使用矩阵快速幂,即:

[fi1,0fi1,1fi1,m]×[B0A1000C0B1A2000C1B2A3000C2B3000000Bm]=[fi,0fi,1fi,m]

最后的答案就是:

ans=fn,mi=2mnmfn,i

#include<cstdio>
#include<iomanip>
#include<cstring>
#define int long long
using namespace std;
const int N=1e2+50,mod=1e9+7,Inv2=500000004;
int n,m,k,A[N],B[N],C[N],a[N],t;
struct Matrix{
int num[N][N];
Matrix(){memset(num,0,sizeof num);}
Matrix operator *(const Matrix &b) const{
Matrix c;
for(int i=0;i<=m;i++){
for(int j=0;j<=m;j++){
for(int k=0;k<=m;k++){
c.num[i][j]=(c.num[i][j]+num[i][k]*b.num[k][j])%mod;
}
}
}
return c;
}
}base,T,One;
void init()
{
for(int i=0;i<=m;i++) One.num[i][i]=1;
base.num[0][t]=1;
for(int j=0;j<=m;j++){//初始化A,B,C
A[j]=(m-j+1)*(m-j+1)%mod;
B[j]=(n-m)*(n-m-1)*Inv2%mod+m*(m-1)*Inv2%mod+(m-j)*(n-2*m+j)%mod+j*(m-j);
C[j]=(j+1)*(n-2*m+j+1)%mod;
B[j]=(B[j]+mod)%mod;
A[j]=(A[j]+mod)%mod;
C[j]=(C[j]+mod)%mod;
}
for(int j=0;j<=m;j++){
if(j) T.num[j-1][j]=A[j];
if(j<m) T.num[j+1][j]=C[j];
T.num[j][j]=B[j];
}
}
Matrix Pow(Matrix a,int b)//矩阵快速幂
{
Matrix ans=One,Base=a;
while(b){
if(b&1){
ans=ans*Base;
}
Base=Base*Base;
b>>=1;
}
return ans;
}
inline int Fast_Pow(int a,int b)
{
int ans=1,base=a;
while(b){
if(b&1) ans=ans*base%mod;
base*=base,base%=mod;
b>>=1;
}
return ans;
}
signed main()
{
scanf("%lld%lld",&n,&k);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
if(!a[i]) m++;
}
for(int i=1;i<=m;i++) t+=(a[i]==0);
init();
base=base*Pow(T,k);
Matrix t=Pow(T,k);
int st=max(2*m-n,0ll);
int sum=0;
for(int i=st;i<=m;i++) sum+=base.num[0][i],sum%=mod;
printf("%lld\n",base.num[0][m]*Fast_Pow(sum,mod-2)%mod);
return 0;
}

本文作者:lxzy

本文链接:https://www.cnblogs.com/Unlimited-Chan/p/16786391.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   lxzy  阅读(29)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.