题目大意:
就是现在有m个位置, 每个位置可以放n种不同的元素中的一个, 问在至少有L个位置上的元素是一样的概率.
大致思路:
首先如果考虑有L, L + 1, .... m个位置上是一样的方案数不好考虑, 但是可以从反面考虑, 计算只有1, 2, ... L - 1个位置有相同元素的方案数, 用总方案数n^m减去即可
如果用dp[i][j]表示用前i种元素填了j个位置(不一定是前j个), 且每个元素都没有使用达到L个, 的方案数的话有
dp[i][j] = sigma(dp[i - 1][j - k]*C[m - (j - k)][k]) (0 <= k <= min(m, l))
即用前i个元素填充j个位置的方案数相当于前i - 1个元素填充了j - k个位置, 第i个元素要填充k个位置, 这k个位置可以来自于剩下的m - (j - k)个位置中的其中k个
那么不满足题意的方案总数是 sigma(dp[i][m]) (1 <= i <= n) 用所有可能的排列方案减去即可得到可行的方案数.
初始化dp[0][0] = 1, 其他值为0即可
很明显只有当l > m时才会没有可能的方案
考虑到计算时数据很大, 使用java方便一些
代码如下:
Result : Accepted Memory : 12914 KB Time : 1031 ms
/*
* Author Gatevin
* Created Time : 2014/12/22 20:16:07
* File Name: Sora_Kasugano.java
*/
import java.util.Scanner;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.util.Map;
import java.util.HashMap;
import java.util.Queue;
import java.util.LinkedList;
import java.io.FileOutputStream;
public class Main{
public static void initC(BigInteger C[][])
{
C[0][0] = BigInteger.ONE;
for(int i = 1; i <= 100; i++)
{
C[i][0] = C[0][0];
for(int j = 1; j <= i; j++)
if(j == i) C[i][j] = C[0][0];
else C[i][j] = C[i - 1][j].add(C[i - 1][j - 1]);
}
return;
}
public static void initdp(BigInteger dp[][])
{
for(int i = 0; i <= 100; i++)
for(int j = 0; j <= 100; j++)
dp[i][j] = BigInteger.ZERO;
return;
}
public static void main(String args[]){
int n, m, l;
Scanner cin = new Scanner(System.in);
BigInteger C[][] = new BigInteger[110][110];
BigInteger dp[][] = new BigInteger[110][110];
initC(C);
while(cin.hasNext())
{
m = cin.nextInt();
n = cin.nextInt();
l = cin.nextInt();
if(l > m)
{
System.out.println("mukyu~");
continue;
}
initdp(dp);
dp[0][0] = BigInteger.ONE;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
for(int k = 0; k <= Math.min(l - 1, j); k++)
dp[i][j] = dp[i][j].add(dp[i - 1][j - k].multiply(C[m - (j - k)][k]));
BigInteger num = BigInteger.ZERO;
BigInteger dem = BigInteger.valueOf(n).pow(m);
for(int i = 1; i <= n; i++)
num = num.add(dp[i][m]);
num = dem.subtract(num);
BigInteger tmp = num.gcd(dem);
num = num.divide(tmp);
dem = dem.divide(tmp);
System.out.println(num + "/" + dem);
}
return;
}
}