ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【循环矩阵乘优化DP】BZOJ 2510 弱题

2020-09-25 18:00:22  阅读:237  来源: 互联网

标签:标号 matrix 弱题 矩阵 times cfrac 2510 DP Mat


题目大意

有 \(M\) 个球,一开始每个球均有一个初始标号,标号范围为 \(1\) ~ \(N\) 且为整数,标号为 \(i\) 的球有 \(a_i\) 个,并保证 \(\sum a_i = M\)。

每次操作等概率取出一个球(即取出每个球的概率均为 \(1\over M\)),若这个球标号为 \(k\ (k < N)\),则将它重新标号为 \(k+1\);若这个球标号为 \(N\),则将其重标号为 \(1\)。(取出球后并不将其丢弃)

现在你需要求出,经过 \(K\) 次这样的操作后,每个标号的球的期望个数。

数据范围

\(N ≤ 1000, M ≤ 100,000,000, K ≤ 2,147,483,647\)。

思路

第一次见到循环矩阵优化 dp 的套路,记录一下。

转移方程很好得到,设 \(f[i][j]\) 表示到第 \(i\) 轮 \(j\) 编号的球的期望个数,转移方程就是

\[f[i][j]=\cfrac{m-1}{m}\ f[i-1][j]+\cfrac{1}{m}\ f[i-1][j-1]\ (2\leq j\leq n) \]

\[f[i][1]=\cfrac{m-1}{m}\ f[i-1][1]+\cfrac{1}{m}\ f[i-1][n] \]

通过 \(K\) 的范围的提示,我们冲一个矩阵快速幂即可,时间效率 \(O(n^3\log K)\)

\(n\leq 1000\)

那没事了。

假设 \(n=4\),我们构造出转移矩阵:

\[ \left[ \begin{matrix} f[i-1][1] & f[i-1][2] & f[i-1][3] & f[i-1][4] \end{matrix} \right] \times \left[ \begin{matrix} \cfrac{m-1}{m} & \cfrac{1}{m} & 0 & 0 \\ 0 & \cfrac{m-1}{m} & \cfrac{1}{m} & 0 \\ 0 & 0 & \cfrac{m-1}{m} & \cfrac{1}{m} \\ \cfrac{1}{m} & 0 & 0 & \cfrac{m-1}{m} \end{matrix} \right] = \left[ \begin{matrix} f[i][1] & f[i][2] & f[i][3] & f[i][4] \end{matrix} \right] \]

我们发现转移矩阵是一个循环矩阵。

那么这个矩阵满足什么性质呢?

我们设第一排的第 \(i\) 个数为 \(k[i]\),我们以 \(k[1]\) 为例:

\[k[1]=a[1][1]\times a[1][1]+a[1][2]\times a[2][1]+a[1][3]\times a[3][1]+a[1][4]\times a[4][1] \]

我们将其对应到第一行的元素,得到:

\[k[1]=k[1]\times k[1]+k[2]\times k[4]+k[3]\times k[3]+k[4]\times k[2] \]

很容易看出性质:

\[k[t]=\sum\limits_{(i+j-2)\equiv t\pmod n}k[i]\times k[j] \]

所以我们只需要记录第一行的状态,用 \(O(n^2\log K)\)转移即可。

代码

#include <bits/stdc++.h>
using namespace std;
const int maxn=1000+10;
int n,m,K;

struct Mat{
    double a[maxn];
    Mat(){
        memset(a,0,sizeof(a));
    }
    friend inline Mat operator *(register const Mat& A,register const Mat& B){
        Mat C;
        for(register int i=1;i<=n;i++)
            for(register int j=1;j<=n;j++)
                C.a[(i+j-2)%n+1]+=A.a[i]*B.a[j];
        return C;
    }
}ans,base;

inline int read(){
    int x=0;bool fopt=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar())if(ch=='-')fopt=0;
    for(;isdigit(ch);ch=getchar())x=(x<<3)+(x<<1)+ch-48;
    return fopt?x:-x;
}

inline void qpow(int b){
    while(b){
        if(b&1)ans=ans*base;
        base=base*base;
        b>>=1;
    }
}

int main(){
    n=read();m=read();K=read();
    for(int i=1;i<=n;i++)
        ans.a[i]=read();
    base.a[1]=1.0*(m-1)/m;
    base.a[2]=1.0/m;
    qpow(K);
    for(int i=1;i<=n;i++)
        printf("%.3lf\n",ans.a[i]);
    return 0;
}

标签:标号,matrix,弱题,矩阵,times,cfrac,2510,DP,Mat
来源: https://www.cnblogs.com/Midoria7/p/13731588.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有