1. 程式人生 > >弱題(循環矩陣1)

弱題(循環矩陣1)

submit 操作 多少 sub nbsp 要求 printf cheng 輸出

問題 D: 弱題

時間限制: 1 Sec 內存限制: 128 MB
提交: 46 解決: 28
[提交][狀態][討論版]

題目描述

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


這道題很容易就能想到用矩陣快速冪,但n^3的時間復雜度顯然是過不去,然後根據DP方程 f[i]=a/n*f[i-1]+(1-b/n)*f[i];所以每一項的轉移都是從本位和前一位轉移而來的,那麽在構建出來的矩陣,無論自乘多少次都能地i+1行是由i行右移的得到的,最後一位到第一位;那麽就可以用矩陣的第一行來表示整個矩陣,我實現的有些麻煩,我有把整個矩陣都重現了出來,其實可以直接由一個關系直接轉移,還有進一步的優化空間;
  1 #include<cmath>
  2 #include<ctime>
  3 #include<cstdio>
  4 #include<cstdlib>
  5 #include<cstring>
  6 #include<iostream>
  7 #include<algorithm>
  8 using namespace std;
  9 int n,m,K;
 10 int num[1010];
 11 double f[1010];
 12 double a[1010][1010];
 13 double
cc[1010]; 14 double b[1010][1010]; 15 void cheng1(){ 16 memset(cc,0,sizeof(cc)); 17 for(int i=1;i<=n;i++){ 18 for(int j=1;j<=n;j++){ 19 cc[i]+=b[j][i]*f[j]; 20 } 21 } 22 for(int i=1;i<=n;i++) 23 f[i]=cc[i]; 24 } 25 double dd[1010][1010]; 26 void cheng2(){ 27 memset(dd,0,sizeof(dd)); 28 for(int i=1;i<=n;i++){ 29 for(int j=1;j<=n;j++){ 30 dd[1][i]+=a[1][j]*a[j][i]; 31 } 32 } 33 for(int i=1;i<=n;i++) 34 a[1][i]=dd[1][i]; 35 for(int i=2;i<=n;i++){ 36 for(int j=1;j<=n;j++){ 37 if(j==1){ 38 a[i][j]=a[i-1][n]; 39 continue; 40 } 41 a[i][j]=a[i-1][j-1]; 42 } 43 } 44 } 45 void cheng3(){ 46 memset(dd,0,sizeof(dd)); 47 for(int i=1;i<=n;i++){ 48 for(int j=1;j<=n;j++){ 49 dd[1][i]+=a[1][j]*b[j][i]; 50 //if(i==1) cout<<"--->"<<a[1][j]<<" "<<b[j][i]<<endl; 51 } 52 } 53 for(int i=1;i<=n;i++){ 54 b[1][i]=dd[1][i]; 55 } 56 for(int i=2;i<=n;i++){ 57 for(int j=1;j<=n;j++){ 58 if(j==1){ 59 b[i][j]=b[i-1][n]; 60 continue; 61 } 62 b[i][j]=b[i-1][j-1]; 63 } 64 } 65 //while(1); 66 } 67 int main(){ 68 //freopen("a.in","r",stdin); 69 // freopen("1.out","w",stdout); 70 scanf("%d%d%d",&n,&m,&K); 71 for(int i=1;i<=n;i++){ 72 scanf("%d",&num[i]); 73 f[i]=num[i]; 74 } 75 for(int i=1;i<=n;i++) b[i][i]=1; 76 a[1][1]+=(double)(m-1)/m; 77 a[n][1]+=(double)1/m; 78 for(int i=2;i<=n;i++){ 79 a[i][i]+=(double)(m-1)/m; 80 a[i-1][i]+=(double)1/m; 81 } 82 /* 83 for(int i=1;i<=n;i++){ 84 for(int j=1;j<=n;j++){ 85 cout<<a[i][j]<<" "; 86 } 87 cout<<endl; 88 }*/ 89 while(K){ 90 if(K&1){ 91 cheng3(); 92 } 93 cheng2(); 94 K=K>>1; 95 } 96 cheng1(); 97 for(int i=1;i<=n;i++){ 98 printf("%.3lf\n",f[i]); 99 } 100 return 0; 101 }

循環矩陣留坑)

弱題(循環矩陣1)