zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    一分钟明确 VS manifest 原理
    关于“鸡脚神”的看法
    Android中Context具体解释 ---- 你所不知道的Context
    解决android3.0版本号以上应用接收不到开机广播问题
    什么是流利语法Fluent Syntax
    vi 命令 使用方法
    TinyXml高速入门(一)
    reactor设计模式
    ActivityGroup+LinearLayout实现iphone风格的底部tab菜单
    使用ActivityGroup来切换Activity和Layout
  • 原文地址:https://www.cnblogs.com/zhsl/p/3253915.html
Copyright © 2011-2022 走看看