bzoj 2510: 弱题 期望dp+循环矩阵乘法

题意

有M个球,一开始每个球均有一个初始标号,标号范围为1~N且为整数,标号为i的球有ai个,并保证Σai = M。
每次操作等概率取出一个球(即取出每个球的概率均为1/M),若这个球标号为k(k < N),则将它重新标号为k + 1;若这个球标号为N,则将其重标号为1。(取出球后并不将其丢弃)
现在你需要求出,经过K次这样的操作后,每个标号的球的期望个数。
N ≤ 1000, M ≤ 100,000,000, K ≤ 2,147,483,647。

分析

如果设f[i,j]表示j次操作后标号为i的球的期望数量,不难得到f[i,j]=f[i,j-1]*(m-1)/m+f[i-1,j-1]/m。
如果n是100的话,就可以直接上矩阵快速幂了。但现在的n是等于1000。
观察状态转移矩阵,不难发现这是一个循环矩阵,也就是其行与行之间或列与列之间都是循环同构的。手玩一下不难发现由两个循环的矩阵乘得的矩阵还是循环的,那么我们就可以只记录循环矩阵的第一行,就可以O(n^2)log得到最终矩阵了。

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;

const int N=1005;

int n,m,k,w[N];
struct Matrix
{
    double a[N];

    void clear(int n)
    {
        for (int i=0;i<n;i++) a[i]=0;
    }
}a;

void mul(Matrix &c,Matrix a,Matrix b)
{
    c.clear(n);
    for (int i=0;i<n;i++)
        for (int j=0;j<n;j++)
            c.a[i]+=a.a[j]*b.a[(i+n-j)%n];
}

Matrix ksm(Matrix x,int y)
{
    Matrix ans;ans.clear(n);ans.a[0]=1;
    while (y)
    {
        if (y&1) mul(ans,ans,x);
        mul(x,x,x);y>>=1;
    }
    return ans;
}

int main()
{
    scanf("%d%d%d",&n,&m,&k);
    for (int i=0;i<n;i++) scanf("%d",&w[i]);
    a.a[0]=(double)(m-1)/m;a.a[1]=(double)1/m;
    a=ksm(a,k);
    for (int i=0;i<n;i++)
    {
        double ans=0;
        for (int j=0;j<n;j++) ans+=(double)w[j]*a.a[(i+n-j)%n];
        printf("%.3lf\n",ans);
    }
    return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值