Divide and Count
Time Limit: 2 Seconds Memory Limit: 65536 KB
Jack has several beautiful diamonds, each of them is unique thus precious. To keep them safe, he wants to divide and store them in different locations. First, he has bought some coffers. These boxes are identical except that their capacities (the number of the diamonds that a box can contain) may diverse. Before he puts his diamonds in, he wants to figure out how many different ways he can store these diamonds into the coffers. He recruits you, a young programmer from Zhejiang University, to give him the answer.
Input:
The input consists of several test cases. Each test case begins with a positive integer N, which indicates the number of the coffers Jack has bought. Then the following N integers are the capacities of each box. The total number of the diamonds Jack has equals to the sum of the capacities of all the coffers.
All the integers given are no greater than 12, you can be assured that a result always fits into a 32-bit integer.
Output:
For every test case, print out an integer representing the number of the different ways Jack can store his diamonds. Each integer is to be printed on a single line.
Sample input:
2 3 3 3 1 2 3
Sample output:
10 60
题意:
杰克有好几颗漂亮的钻石,每一颗都是独一无二的。为了保护他们的安全,他想把它们分开存放在不同的地方。首先,他买了一些小金库。这些盒子是相同的,只是它们的容量(盒子所能容纳的钻石的数目)可能是不同的。在他把钻石放进去之前,他想弄清楚他能把这些钻石存放在金库里有多少种不同的方式。他招募你,一个来自浙江大学的年轻程序员,给他答案。
输入:
输入由几个测试用例组成。每个测试用例以一个正整数n开头,这表示杰克购买的金库的数量。接下来的n个整数是每个盒子的容量。杰克钻石的总数等于所有金库的总和。
给定的所有整数不大于12,可以确保结果总是适合32位整数。
输出:
对于每个测试用例,打印出一个整数,表示杰克存储钻石的不同方式的数量。每个整数都要在一行上打印。
思路:
排列组合
我们来手模一下第一个样例:2 3 3 我们先往第一个金库中装钻石,这样的话我们有C36(比较丑,凑活着看吧)种方案,我们在往第二个匣子中放钻石,这是我们已经把3个钻石放入了第一个匣子中,也就是说我们这是还剩下6-3颗钻石,我们把这些钻石放入这个匣子中,有C33种方案。但是我们这样算出来肯定是不对的,因为容积相同的金库完全相同,那么也就是说我们要除去匣子相同的方案数,但是除什么呢??!这也正是我与一位大佬发生争执的地方。我认为应该是除相同个数的阶乘,而他认为除相同的个数。
好,我们先不看这个样例,因为看不出来啊、、、、
我们自己手模样例,就找个简单的吧,3 1 1 1 我们跟上面说的一样,先往第一个匣子中放钻石,这样我们有C13种方案,我们往第二个匣子中放钻石这是我们有3-1颗钻石,我们找出一个来放入第二个匣子中,这样我们有C12种方案数,最后一个我也就不再写了,这样我们求出来一共有6种方法,但是我们知道这三个匣子是完全相同的,那么也就是说我们只有一种方法,那么这样的话我们该除几就显而易见了。
至于题的这个公式,我想各位大佬上面的解释的时候应该也都能看明白(也可能本蒟蒻写的一点都不明白)那我就不啰嗦了
代码:
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #define N 20 using namespace std; long long ans; int n,m,w,tot,a[N],num[N]; int read() { int x=0,f=1; char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1; ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘; ch=getchar();} return x*f; } int jie(int x,int y) { int sum=1; for(int i=x;i<=y;i++) sum*=i; return sum; } int main() { while(~scanf("%d",&n)) { for(int i=1;i<=12;i++) a[i]=0; ans=1;tot=0; for(int i=1;i<=n;i++) num[i]=read(),a[num[i]]++,tot+=num[i]; for(int i=1;i<=n;i++) { w=tot-num[i]+1; ans*=jie(w,tot)/jie(1,num[i]); tot-=num[i]; } for(int i=1;i<=12;i++) if(a[i]) ans=ans/jie(1,a[i]); cout<<ans<<endl; } return 0; }