1. 程式人生 > >Throwing Dice LightOJ - 1064 || (勉強能用的)分數類

Throwing Dice LightOJ - 1064 || (勉強能用的)分數類

ret 前綴和 加法 spa 結構體 dice span lan const

Throwing Dice LightOJ - 1064

方法:

設ans[i][j]表示i個骰子點數恰好為j的概率。那麽ans[1][1]到ans[1][6]都為1/6。

顯然,$ans[i][j]=sum\{ans[i-1][j-k]\}(1<=k<=6,j>k)$

n和x上限很小,直接處理出所有點數恰好為某個值的結果,然後再做一遍類似前綴和的東西處理出所有點數大於等於某個值的結果。這裏答案需要分數,於是亂寫了一個分數結構體。

分數運算(沒有優化的):

初始化空的分數:分子為0,分母為1

加法:先通分,然後加分子,然後約分

乘法:先互相約分,然後分子分母分別相乘

錯誤次數:1次

錯誤原因:由於把前綴和的範圍限制與原數據的範圍限制搞混,66行>=0寫成>=i,導致WA

 1 #include<cstdio>
 2 typedef long long LL;
 3 LL gcd(LL a,LL b)
 4 {
 5     LL t;
 6     while(b!=0)
 7     {
 8         t=a;
 9         a=b;
10         b=t%b;
11     }
12     return a;
13 }
14 struct X
15 {
16     LL a,b;
17 X() 18 { 19 a=0;b=1; 20 } 21 X(int x,int y) 22 { 23 a=x;b=y; 24 } 25 X operator+(const X& c) 26 { 27 X ans; 28 LL tmp=gcd(b,c.b); 29 ans.b=b/tmp*c.b; 30 ans.a=ans.b/b*a+ans.b/c.b*c.a; 31 tmp=gcd(ans.a,ans.b);
32 ans.a/=tmp; 33 ans.b/=tmp; 34 return ans; 35 } 36 X operator*(const X& c) 37 { 38 LL tmp1=gcd(a,c.b),tmp2=gcd(b,c.a); 39 X ans; 40 ans.a=a/tmp1*c.a/tmp2; 41 ans.b=b/tmp2*c.b/tmp1; 42 return ans; 43 } 44 void print() 45 { 46 if(b==1) 47 printf("%lld",a); 48 else 49 printf("%lld/%lld",a,b); 50 } 51 }ans[26][151],ans2[26][151]; 52 LL T,TT,n,x; 53 int main() 54 { 55 int i,j,k; 56 for(i=1;i<=6;i++) 57 ans[1][i]=(X){1,6}; 58 for(i=2;i<=25;i++) 59 for(j=i;j<=6*i;j++) 60 for(k=1;k<=6;k++) 61 if(j-k>0) 62 ans[i][j]=ans[i][j]+ans[i-1][j-k]*ans[1][1];//ans[1][1]就是1/6 63 for(i=1;i<=25;i++) 64 { 65 ans2[i][6*i]=ans[i][6*i]; 66 for(j=6*i-1;j>=0;j--) 67 ans2[i][j]=ans2[i][j+1]+ans[i][j]; 68 } 69 scanf("%lld",&T); 70 for(TT=1;TT<=T;TT++) 71 { 72 scanf("%lld%lld",&n,&x); 73 printf("Case %lld: ",TT); 74 ans2[n][x].print(); 75 puts(""); 76 } 77 return 0; 78 }

Throwing Dice LightOJ - 1064 || (勉強能用的)分數類