【概率DP】 ZOJ 3380 Patchouli's Spell Cards

通道

题意:有m个位置,每个位置填入一个数,数的范围是1~n,问至少有L个位置的数一样的概率

思路:

总数是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));
        }
    }
}
View Code

 

posted @ 2015-08-12 20:39  mithrilhan  阅读(198)  评论(0编辑  收藏  举报