ZOJ-3380 Patchouli’s Spell Cards DP, 组合计数

  题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3380

  题意:有m种不同的元素,每种元素都有n种不同的相位,现在假设有每种元素各一个,其相位是等概率随机的。如果几个元素的相位相同,那么帕琪就可以把它们组合发动一个符卡(Spell Card)。现在问帕琪能够发动等级不低于l,即包含l个相同相位的不同元素的附卡的概率。

  首先所有的总数是n^m,然后只要求满足情况的数目了,对于 l >m/2我们可以直接用组合数来求的,即n*Σ( C(m,i)*(n-1)^(m-i) ),如果 l <= m/2就麻烦一些了,因为这里存在重复的情况,组合数求比较麻烦,于是我们可以用DP,f[i][j]表示前 i 个数放在 j 个位置并且相同的元素个数小于 l 的数目,f[i][j]=sum{dp[i-1][j-k]*choose[m-(j-k)][k] | k≤j && k<l}。然后这题大数,直接用Java了。。。

  上面是O(nml)的复杂度,还有一个O(mml)的:

dp[i,j]  表示用i个数字在m个里放了j个位置,i表示有i个,不一定是[1,i]
dp[i,j] = ∑ dp[i-1,j-k]*C[m-(j-k),k]*(n-(i-1))    1≤k≤j , k<l
最后答案为  ∑ dp[i,m]/i!      刚才用到的是乘法原理,是排列,要转化为组合数!

 1 //STATUS:Java_AC_1240MS_20194KB
 2 import java.util.*;
 3 import java.math.*;
 4 import java.io.*;
 5 import java.text.*;
 6 
 7 public class Main {
 8     static final int N=101;
 9     static BigInteger[][] f=new BigInteger[N][N];
10     static BigInteger[][] C=new BigInteger[N][N];
11     public static void main(String args[]){
12         Scanner cin = new Scanner (new BufferedInputStream(System.in));
13         int i,j,k;
14         for(i=0;i<N;i++)C[i][0]=C[i][i]=BigInteger.valueOf(1);
15         for(i=2;i<N;i++){
16             for(j=1;j<i;j++)
17                 C[i][j]=C[i-1][j-1].add(C[i-1][j]);
18         }
19         int n,m,l;
20         BigInteger tot,cnt;
21         while(cin.hasNext())
22         {
23             m=cin.nextInt();
24             n=cin.nextInt();
25             l=cin.nextInt();
26             if(l>m){
27                 System.out.println("mukyu~");
28                 continue;
29             }
30             tot=BigInteger.valueOf(n);
31             tot=tot.pow(m);
32             cnt=BigInteger.ZERO;
33             if(l>m/2){
34                 for(i=l;i<=m;i++){
35                     cnt=cnt.add(C[m][i].multiply( BigInteger.valueOf(n-1).pow(m-i) ));
36                 }
37                 cnt=cnt.multiply(BigInteger.valueOf(n));
38             }
39             else {
40                 for(i=0;i<=n;i++)
41                     for(j=0;j<=m;j++)f[i][j]=BigInteger.ZERO;
42                 f[0][0]=BigInteger.ONE;
43                 for(i=1;i<=n;i++){
44                     for(j=0;j<=m;j++){
45                         for(k=0;k<=j && k<l;k++){
46                             f[i][j]=f[i][j].add(f[i-1][j-k].multiply(C[m-j+k][k]));
47                         }
48                     }
49                 }
50                 cnt=tot;
51                 cnt=cnt.subtract(f[n][m]);
52             }
53             BigInteger t=cnt.gcd(tot);
54             cnt=cnt.divide(t);
55             tot=tot.divide(t);
56             
57             System.out.println(cnt+"/"+tot);
58         }
59     }
60 }

 

posted @ 2013-08-12 20:37  zhsl  阅读(387)  评论(0编辑  收藏  举报