【BZOJ 2510】 2510: 弱题 (矩阵乘法、循环矩阵的矩阵乘法)

2510: 弱题

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 374  Solved: 196

Description

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

Input

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

Output

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

Sample Input

2 3 2
3 0

Sample Output

1.667
1.333

HINT

【样例说明】

第1次操作后,由于标号为2球个数为0,所以必然是一个标号为1的球变为标号为2的球。所以有2个标号为1的球,有1个标号为2的球。

第2次操作后,有1/3的概率标号为2的球变为标号为1的球(此时标号为1的球有3个),有2/3的概率标号为1的球变为标号为2的球(此时标号为1的球有1个),所以标号为1的球的期望个数为1/3*3+2/3*1 = 5/3。同理可求出标号为2的球期望个数为4/3。



【数据规模与约定】

对于10%的数据,N ≤ 5, M ≤ 5, K ≤ 10;

对于20%的数据,N ≤ 20, M ≤ 50, K ≤ 20;

对于30%的数据,N ≤ 100, M ≤ 100, K ≤ 100;

对于40%的数据,M ≤ 1000, K ≤ 1000;

对于100%的数据,N ≤ 1000, M ≤ 100,000,000, K ≤ 2,147,483,647。




Source

 

【分析】

  综合题表里面目测的一道【稀少的】可做题。。

  显然,矩阵乘法嘛。。$f[i][j]=f[i-1][j]*\dfrac{m-1}{m}+f[i-1][j-1]*\dfrac{1}{m}$

  然后一个厉害的东西就是A,B是循环矩阵(就是矩阵的下一行是上一行循环右移一位得到的),那么A*B=C的C也是循环矩阵。

  只需求第一行就可以求出整个C。

  所以是$n^2 log$

 

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 6 using namespace std;
 7 #define Maxn 1010
 8 
 9 int a[Maxn];
10 int n,m,k;
11 
12 struct node
13 {
14     double w[Maxn][Maxn];
15 }t[5];
16 
17 void mul(int x,int y,int z)
18 {
19     for(int i=1;i<=n;i++)
20      for(int j=1;j<=n;j++) t[2].w[i][j]=0;
21     for(int k=1;k<=n;k++)
22      for(int j=1;j<=n;j++)
23       t[2].w[1][j]+=t[y].w[1][k]*t[z].w[k][j];
24     for(int j=1;j<=n;j++) t[x].w[1][j]=t[2].w[1][j];
25     for(int i=2;i<=n;i++)
26     {
27       for(int j=1;j<=n;j++)
28         t[x].w[i][j]=t[x].w[i-1][j-1==0?n:j-1];
29     }
30 }
31 
32 void qpow(int b)
33 {
34     for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) t[1].w[i][j]=0;
35     for(int i=1;i<=n;i++) t[1].w[i][i]=1.0;
36     while(b)
37     {
38         if(b&1) mul(1,0,1);
39         mul(0,0,0);
40         b>>=1;
41     }
42 }
43 
44 int main()
45 {
46     scanf("%d%d%d",&n,&m,&k);
47     for(int i=1;i<=n;i++) scanf("%d",&a[i]);
48     for(int i=1;i<=n;i++)
49     {
50         for(int j=1;j<=n;j++) t[0].w[i][j]=0;
51         t[0].w[i][i]=1.0-1.0/m;
52         t[0].w[i][i-1==0?n:i-1]=1.0/m;
53     }
54     qpow(k);
55     for(int i=1;i<=n;i++)
56     {
57         double ans=0;
58         for(int j=1;j<=n;j++)
59         {
60             ans+=a[j]*t[1].w[i][j];
61         }
62         printf("%.3lf\n",ans);
63     }
64     return 0;
65 }
View Code

 

2017-04-10 20:47:14

posted @ 2017-04-10 20:47  konjak魔芋  阅读(291)  评论(0编辑  收藏  举报