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 }

 

你可能感兴趣的:(SPEL)