ZOJ 3380 Patchouli's Spell Cards(概率DP)

Patchouli's Spell Cards

Time Limit: 7 Seconds      Memory Limit: 65536 KB

Patchouli Knowledge, the unmoving great library, is a magician who has settled down in the Scarlet Devil Mansion (紅魔館). Her specialty is elemental magic employing the seven elements fire, water, wood, metal, earth, sun, and moon. So she can cast different spell cards like Water Sign "Princess Undine", Moon Sign "Silent Selene" and Sun Sign "Royal Flare". In addition, she can combine the elements as well. So she can also cast high-level spell cards like Metal & Water Sign "Mercury Poison" and Fire, Water, Wood, Metal & Earth Sign "Philosopher's Stones" .

Assume that there are m different elements in total, each element has n different phase. Patchouli can use many different elements in a single spell card, as long as these elements have the same phases. The level of a spell card is determined by the number of different elements used in it. When Patchouli is going to have a fight, she will choose m different elements, each of which will have a random phase with the same probability. What's the probability that she can cast a spell card of which the level is no less than l, namely a spell card using at least l different elements.

Input

There are multiple cases. Each case contains three integers 1 ≤ m, n, l ≤ 100. Process to the end of file.

Output

For each case, output the probability as irreducible fraction. If it is impossible, output "mukyu~" instead.

Sample Input

7 6 5
7 7 7
7 8 9

Sample Output

187/15552
1/117649
mukyu~

References

上海アリス幻樂団

acm_x_touhou


Author: WU, Zejun
Source: ACM × Touhou
Contest: ZOJ Monthly, August 2010

 

 

 

/*
 * ZOJ 3380
 * 题目意思:有m个位置,每个位置填入一个数,数的范围是1~n,问至少有L个位置的数一样的概率
 * 输出要是最简分数的形式,所以用大数JAVA
 * 至少有L个位置一样,就是L,L+1,L+2····m个位置一样。
 * 我们从反面来考虑,总数是n^m,我们求没有L个位置一样的数的概率
 * 设 dp[i][j]表示用前i个数,填充j个位置的方案数(要符合没有L个位置是一样的数)
 * dp[i][j]=dp[i-1][j]+Sigm( dp[i-1][j-k]*C[m-(j-k)][k]  ) k<=j&&k<L
 * 其实就是看第i个数,可以不填,填一个位置,两个位置······这样累加过来。
 * 那么最后的答案就是 (n^m-dp[1~n][m])/(n^m)
 */

 

主要是大数比较麻烦。所以就用JAVA写了,当是练习下JAVA吧!

 

/*
 * ZOJ 3380
 * 题目意思:有m个位置,每个位置填入一个数,数的范围是1~n,问至少有L个位置的数一样的概率
 * 输出要是最简分数的形式,所以用大数JAVA
 * 至少有L个位置一样,就是L,L+1,L+2····m个位置一样。
 * 我们从反面来考虑,总数是n^m,我们求没有L个位置一样的数的概率
 * 设 dp[i][j]表示用前i个数,填充j个位置的方案数(要符合没有L个位置是一样的数)
 * dp[i][j]=dp[i-1][j]+Sigm( dp[i-1][j-k]*C[m-(j-k)][k]  ) k<=j&&k<L
 * 其实就是看第i个数,可以不填,填一个位置,两个位置······这样累加过来。
 * 那么最后的答案就是 (n^m-dp[1~n][m])/(n^m)
 */
import java.util.*;
import java.io.*;
import java.math.*;
public class Main
{
    static BigInteger[][] dp=new  BigInteger[110][110];
    static BigInteger[][] C=new BigInteger[110][110];//组合数
    public static void main(String arg[])
    {
        Scanner cin=new Scanner(new BufferedInputStream(System.in));
        for(int i=0;i<105;i++)
        {
            C[i][0]=C[i][i]=BigInteger.ONE;
            for(int j=1;j<i;j++)
                C[i][j]=C[i-1][j-1].add(C[i-1][j]);
        }
        int N,M,L;
        while(cin.hasNext())
        {
            M=cin.nextInt();
            N=cin.nextInt();
            L=cin.nextInt();
            BigInteger tol=BigInteger.valueOf(N).pow(M);
            if(L>M)
            {
                System.out.println("mukyu~");
                continue;
            }
            if(L>M/2)//这个时候可以直接用组合数求出来
            {
                BigInteger ans=BigInteger.ZERO;
                for(int i=L;i<=M;i++)
                    ans=ans.add(C[M][i].multiply(BigInteger.valueOf(N-1).pow(M-i)));
                ans=ans.multiply(BigInteger.valueOf(N));
                BigInteger gcd=ans.gcd(tol);
                System.out.println(ans.divide(gcd)+"/"+tol.divide(gcd));
                continue;
            }
            for(int i=0;i<=N;i++)
                 for(int j=0;j<=M;j++)
                 {
                     dp[i][j]=BigInteger.ZERO;
                 }
            dp[0][0]=BigInteger.ONE;
            for(int i=1;i<=N;i++)
                for(int j=1;j<=M;j++)
                {
                    for(int k=0;k<L&&k<=j;k++)
                        dp[i][j]=dp[i][j].add(dp[i-1][j-k].multiply(C[M-(j-k)][k]));
                }
           BigInteger ans=BigInteger.ZERO;
           for(int i=1;i<=N;i++)
               ans=ans.add(dp[i][M]);    
           ans=tol.subtract(ans);
           BigInteger gcd=ans.gcd(tol);
           System.out.println(ans.divide(gcd)+"/"+tol.divide(gcd));
        }
    }
}

 

posted on 2012-10-06 14:57  kuangbin  阅读(1326)  评论(0编辑  收藏

导航

统计

JAVASCRIPT: