弱题题解

Posted Forever_goodboy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了弱题题解相关的知识,希望对你有一定的参考价值。

题面:

题目描述

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

输入

第1行包含三个正整数NMK,表示了标号与球的个数以及操作次数。
第2行包含N非负整数ai,表示初始标号为i的球有ai个。

输出

应包含N行,第i行为标号为i的球的期望个数,四舍五入保留3位小数。

样例输入

2 3 2
3 0

样例输出

1.667
1.333
考试时想到了一个最暴力的dp转移,竟然骗到了55分,数据太水QAQ。。。。。。
递推公式其实很好想,f[i][j]代表到第i个球到第j次的期望个数,但是发现第二维没有办法开,于是滚动数组,用O(n*k)的效率转移
f[i][j]=f[i][j^1]+f[i-1][j^1]/m-f[i][j^1]/m;
    =(m-1)/m*f[i][j^1]+f[i-1][j^1]
发现这个玩意其实可以矩阵优化,先构造矩阵,但是又发现如果普通矩阵n^3的效率肯定要T,
其实这个矩阵不管自乘多少次第i行都是由第i-1行右移一位,所以只需要算出第一行在递推转移即可
于是时间为O(n^2*log)
 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<algorithm>
 5 using namespace std;
 6 int n,m,k;
 7 double f[1005],a[1005][1005],temp[1005];
 8 void init() {
 9     double p1=(double)(m-1)/m,p2=(double)1/m;
10     for(int i=1; i<=n; i++) {
11         a[i][i]=p1;
12     }
13     for(int i=1; i<n; i++) {
14         a[i][i+1]=p2;
15     }
16     a[n][1]=p2;
17 }
18 int main() {
19     scanf("%d%d%d",&n,&m,&k);
20     for(int i=1; i<=n; i++) {
21         scanf("%lf",&f[i]);
22     }
23     init();
24     for(; k; k>>=1) {
25         if(k&1) {
26             for(int i=1; i<=n; i++) {
27                 temp[i]=0;
28                 for(int j=1; j<=n; j++) {
29                     temp[i]+=f[j]*a[j][i];
30                 }
31             }
32             for(int i=1; i<=n; i++) {
33                 f[i]=temp[i];
34             }
35         }
36         for(int i=1; i<=n; i++) {
37             temp[i]=0;
38             for(int j=1; j<=n; j++) {
39                 temp[i]+=a[1][j]*a[j][i];
40             }
41         }
42         for(int i=1; i<=n; i++) {
43             a[1][i]=temp[i];
44         }
45         for(int i=2; i<=n; i++) {
46             a[i][1]=a[i-1][n];
47             for(int j=2; j<=n; j++) {
48                 a[i][j]=a[i-1][j-1];
49             }
50         }
51     }
52     for(int i=1; i<=n; i++) {
53         printf("%0.3lf\\n",f[i]);
54     }
55     return 0;
56 }

 

 

以上是关于弱题题解的主要内容,如果未能解决你的问题,请参考以下文章

弱题(循环矩阵1)

bzoj2510: 弱题

BZOJ2510弱题 期望DP+循环矩阵乘法

Java 求解划分字母区间

微信小程序代码片段

VSCode自定义代码片段——CSS选择器