ZOJ 3380 Patchouli's Spell Cards [基础DP+大数]

Description

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.


题意:

抽象的来说,就是给你M个不同的球,N种颜色,现在给球染色,问至少有L个球同一种颜色的概率。


范围:

N,M,L<=100


解法:

总方案数很好算,为N^M,剩下的就是求至少L个球同色的方案数,其可以转换为 (总方案数-每种颜色至多L-1个球的方案数)。

然后就是很明显的DP了,DP[I][J]表示已放完I种颜色,剩下J个球的方案数,那么转移方程为

DP[I+1][J-K]+=DP[I][J]*C(J,K) 其中C()为组合数,K为当前颜色装的球数。

注意会暴longlong,需要用大数,我这里使用了JAVA写大数


import java.math.BigInteger;
import java.util.Scanner;
public class Main{
	static BigInteger[][] dp = new BigInteger[111][111];
	static BigInteger[][] c = new BigInteger[111][111];
	static void init(){
		c[0][0]=BigInteger.valueOf(1);
		for(int i=1;i<=100;i++){
			c[i][0]=c[i][i]=BigInteger.valueOf(1);
			for(int j=1;j<i;j++){
				c[i][j]=c[i-1][j-1].add(c[i-1][j]);
			}
		}
	}
	static int min(int x,int y){
		return x<y?x:y;
	}
	static void solve(int m,int n,int l){
		BigInteger fm=BigInteger.valueOf(n).pow(m);
		for(int i=0;i<=n+1;i++)
			for(int j=0;j<=m;j++)dp[i][j]=BigInteger.ZERO;
		dp[0][m]=BigInteger.ONE;
		for(int i=0;i<n;i++){
			for(int j=0;j<=m;j++){
				for(int k=0;k<=min(j,min(m,l-1));k++){
					dp[i+1][j-k]=dp[i+1][j-k].add(dp[i][j].multiply(c[j][k]));
				}
			}
		}
		BigInteger fz=dp[n][0];
		BigInteger gcd=fm.gcd(fz);
		fz=fm.subtract(fz).divide(gcd);
		fm=fm.divide(gcd);
		System.out.println(fz+"/"+fm);
	}
	public static void main(String[] args) {
		init();
		int m,n,l;
		Scanner sc = new Scanner(System.in);
		while(sc.hasNext()){
			m=sc.nextInt();
			n=sc.nextInt();
			l=sc.nextInt();
			if(l>m)System.out.println("mukyu~");
			else solve(m,n,l);
		}
		sc.close();
	}
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值