UVA 10759 Dice Throwing
题意为抛n个骰子凑成的点数和大于或等于x的概率,刚开始用暴力枚举,虽然AC了,但时间为2.227s,然后百度了下别人的做法,交了一遍,靠,0.000s,然后看了下思路,原来是dp,在暴力的基础上记忆化搜索,把所有可能枚举出来再累加,然后自己也打了一遍,0.000sA了,做法是开一个二维数组,第一维是骰子个数,第二维是和x,然后一个只有可能是1,2,3,4,5,6,倒两个骰子时是1+1,2,3,4,5,6 2+1,2,3,4,5,6 3+...累加向上推即可
1 //暴力做法,2.227s 2 #include<cstdio> 3 #include<cmath> 4 #include<iostream> 5 #include<cstring> 6 7 using namespace std; 8 9 typedef long long ll; 10 11 int n,x,dice[7],prime[10]={2,3,5,7,11,13,17,19,23},fact[30][10];//n个dice,x为和,dice[i]点数为i的骰子个数 12 ll fz,fm; 13 14 void fact_table()//fact[i] i!的质因分解表 15 { 16 memset(fact,0,sizeof(fact)); 17 for(int i=2;i<=24;i++) 18 { 19 int x=i; 20 for(int j=0;x>=prime[j]&&j<9;j++) 21 while(x%prime[j]==0) 22 { 23 fact[i][j]++; 24 x/=prime[j]; 25 } 26 } 27 for(int i=3;i<=24;i++) 28 { 29 for(int j=0;j<9;j++) 30 fact[i][j]+=fact[i-1][j]; 31 } 32 } 33 34 void A6n()//dice[1]个1,dice[2]个2...时的种数=n!/(dice[1]!*dice[2]!*dice[3]!*dice[4]!*dice[5]!*dice[6]!) 35 { 36 ll x=1; 37 int fn[10],fnum[10]; 38 memcpy(fn,fact[n],sizeof(fn)); 39 for(int i=1;i<=6;i++)//n!/dice[i]! 40 { 41 memcpy(fnum,fact[dice[i]],sizeof(fnum)); 42 for(int j=0;j<9;j++) 43 fn[j]-=fnum[j]; 44 } 45 for(int i=0;i<9;i++) 46 x*=pow(prime[i],fn[i]); 47 /*for(int i=1;i<=6;i++) 48 printf("%d ",dice[i]); 49 puts("");*/ 50 fz+=x;//累加倒分子 51 } 52 53 void C6n(int u,int n,int sum)//枚举所有可能 54 { 55 if(u==6) 56 { 57 dice[u]=n; 58 sum+=u*n; 59 if(sum>=x) A6n();//和大于或等于x就加到分子中 60 return; 61 } 62 for(int i=0;i<=n;i++) 63 { 64 dice[u]=i; 65 C6n(u+1,n-i,sum+i*u); 66 } 67 } 68 69 void slove() 70 { 71 if(6*n<x) 72 { 73 puts("0"); 74 return; 75 } 76 fz=0; 77 C6n(1,n,0); 78 int e2,e3; 79 e2=e3=n;//6^n=2^e2*2^e3 80 //printf("fz=%lld\n",fz); 81 while(fz%2==0) 82 { 83 fz>>=1; 84 e2--; 85 if(!e2) break;//e2==0时要break掉,不然变成2的负数次方会wa 86 } 87 while(fz%3==0) 88 { 89 fz/=3; 90 e3--; 91 if(!e3) break; 92 } 93 //printf("fz=%lld e2=%d e3=%d\n",fz,e2,e3); 94 fm=pow(3,e3)*pow(2,e2); 95 if(fz==0) puts("0"); 96 else if(fm==1) puts("1"); 97 else printf("%lld/%lld\n",fz,fm); 98 } 99 100 int main() 101 { 102 //freopen("/home/user/桌面/in","r",stdin); 103 fact_table(); 104 while(scanf("%d%d",&n,&x)==2&&(n||x)) 105 slove(); 106 return 0; 107 }
1 #include<cstdio> 2 #include<cmath> 3 #include<iostream> 4 #include<cstring> 5 6 using namespace std; 7 8 typedef long long ll; 9 10 int n,x;//n个dice,x为和 11 ll fz,fm,fact[30][155]; 12 13 void fact_table() 14 { 15 memset(fact,0,sizeof(fact)); 16 for(int i=1;i<=6;i++) 17 fact[1][i]=1; 18 for(int i=2;i<=24;i++)//fact[i][j]表示i个骰子和为j的种数 19 for(int j=1;j<=6;j++) 20 for(int k=i-1;k<=(i-1)*6;k++) 21 fact[i][k+j]+=fact[i-1][k]; 22 /*for(int i=1;i<=24;i++) 23 { 24 printf("%d: ",i); 25 for(int j=i;j<i*6;j++) 26 printf("%lld ",fact[i][j]); 27 printf("\n"); 28 }*/ 29 } 30 void slove() 31 { 32 int e2=n,e3=n; 33 fz=0; 34 for(int i=x;i<=150;i++) 35 fz+=fact[n][i]; 36 while(fz%2==0) 37 { 38 fz>>=1; 39 e2--; 40 if(!e2) break; 41 } 42 while(fz%3==0) 43 { 44 fz/=3; 45 e3--; 46 if(!e3) break; 47 } 48 fm=pow(3,e3)*pow(2,e2); 49 if(fz==0) puts("0"); 50 else if(fm==1) puts("1"); 51 else printf("%lld/%lld\n",fz,fm); 52 } 53 54 int main() 55 { 56 //freopen("in","r",stdin); 57 fact_table(); 58 while(scanf("%d%d",&n,&x)==2&&(n||x)) slove(); 59 return 0; 60 }