1.题目链接。题目大意:给出一些字符串,问由这些字符串形成的排列有多少种。
2.是一个多重排列的裸题,主要还是想说一下多重集合的排列问题。
3.首先定义多重集合:常规意义下的集合是满足集合的三大性质:确定性,唯一性,无序性。其中唯一性就是说集合内的某个元素是唯一的,不会存在两个相同的元素。多重集合是普通意义集合的推广,不再满足唯一性,其他两条仍然满足。多重集合就是说一个集合内部的元素是可以重复的:定义为:.其中,x1,x2,x3...xn是这个集合内的元素,a1,a2,...an代表这个元素出现的次数,也叫做这个元素的重数。当集合存在n个元素时:a1+a2+a3+a4..an=n,在这样的集合下,我们考虑排列问题。
4.多重集合意义下的排列:我们知道,传统的排列就是:n!.n是集合内元素的个数,但是这里就显然不是了,因为一个很简单的情况:当相同的元素排在一起的时候,这个时候他们内部无论怎么排,都是一种情况,所以显然不再是n!.其实结果也是很好推导的:
我们知道:a1+a2+a3+a4...an=n.我们分步考虑,对于排列好的结果,我们首先考虑x1的位置,由于x1是具有a1个的,所以我们需要在n个位置中选出a1个给x1.这样就是C(n,a1).处理好x1之后,我们考虑x2,同样拿出a2个位置给它,由于剩下的位置就是:n-a1个,所以方案数就是C(n-a1,a2).可以看出来这就是一个递归的过程,那么答案就是:C(n,a1)*C(n-a1,a2)....C(n-a1-a2...an-1,an).
化简一下就是:
到这里就可以解决这个问题了。
其实这里只是解决了这个集合的n排列(X排列指的是这个排列中含有X个元素),也就是全排列。但是对于这个多重集合的任意r排列(r<=n)该怎么解决?可以提供两种方法:1.母函数.2.分类讨论。至于母函数,不再多说,因为不是一个很难的东西。我们简答的说一下如何分类讨论,这只适用于数据比较特殊的情况下。
比如我们考虑这样一个集合:
S={3*a,2*b,4*c},求这个集合的8排列。我们可以看出来,集合元素其实是有9个的,8排列就是少了一个元素,那么就是这三个元素分别少一个的情况下,求一下这个排列的数量,最后加起来就是答案。
也就是求S1={2*a,2*b,4*c},S2={3*a,1*b,4*c},S3={3*a,2*b,3*c}这三个集合的全排列,然后相加即可。
可以看出来,这种数据很特殊的时候,还是可以转化为全排列做的。
最后给出这个题的代码,显示是大数,JAVA实现。
package BIgIn;
import java.util.*;
import java.math.*;
public class Main
{
public static int N=30;
public static BigInteger ans[]=new BigInteger[N];
public static BigInteger getFac(int n)
{
BigInteger res=new BigInteger("1");
BigInteger cur=new BigInteger ("1");
for(int i=1;i<=n;i++)
{
res=res.multiply(cur);
cur=cur.add(BigInteger.ONE);
}
return res;
}
public static void main(String []args)
{
int T;
Scanner cin=new Scanner(System.in);
while(cin.hasNext())
{
T=cin.nextInt();
if(T==0)break;
BigInteger ans1=new BigInteger("1");
int cur=0;
// System.out.println("当前的答案是:"+ans1);
int sum=0;
for(int i=1;i<=T;i++)
{
cur=cin.nextInt();
sum+=cur;
ans1=ans1.multiply(getFac(cur));
}
BigInteger fenzi=getFac(sum);
ans1=fenzi.divide(ans1);
System.out.println(ans1);
}
}
}