• 【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
    ",ans);
    63     }
    64     return 0;
    65 }
    View Code

    2017-04-10 20:47:14

  • 相关阅读:
    test
    封装和构造方法
    面向对象
    数组的排序
    UDP编程(八)
    多的是面向对象你不知道的事
    面向对象组合的使用
    类成员的进一步阐述
    面向对象初始
    吾日三省吾身
  • 原文地址:https://www.cnblogs.com/Konjakmoyu/p/6690842.html
Copyright © 2020-2023  润新知