Codeforces Contest 1151 F Sonya and Informatics —— 矩阵快速幂

202 篇文章 5 订阅
4 篇文章 0 订阅

This way

题意:

给你一串值包含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);
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值