P1866 编号 题解

题目描述

太郎有N只兔子,现在为了方便识别它们,太郎要给他们编号。兔子们向太郎表达了它们对号码的喜好,每个兔子i想要一个整数,介于1和Maxnumber[i]之间(包括1和Maxnumber[i])。当然,每个兔子的编号是不同的。现在太郎想知道一共有多少种编号的方法。

你只用输出答案mod 1000000007即可。如果这是不可能的,就输出0.

输入格式

第一行是一个整数N。(1≤N≤50)

第二行N个整数Maxnumber[i]。(1≤Maxnumber[i]≤1000)

输出格式

一个整数

输入输出样例

输入 #1
2
5 8
输出 #1
35

题目分析

通过乘法原理,可知

若某个对象分为n个环节,第1个环节有m1个元素,第2个环节有m2个元素,……,第n个环节有mn个元素,则该对象有 N=m1×m2×m3×…×mn 种序列。
将此结论代入题目,可得:

若Maxnumber数组已被从小到大排序(排序方法很多,这里用桶排序),则:ans分为N个环节,第1个环节有Maxnumber[0]-0个元素,第2个环节有Maxnumber[1]-1个元素,……,第N个环节有Maxnumber[N-1]-(N-1)个元素,则ans有 (Maxnumber[0]-0)*(Maxnumber[1]-1)*…(Maxnumber[N-1]-(N-1))种序列。

(因为第2个环节可选元素必与第1个环节选到的元素重复,要减1;第3个环节可选元素必与第1个环节选到的元素,第2个环节选到的元素重复,要减2…第N个环节可选元素必与第1个环节选到的元素,第2个环节选到的元素,…,第(N-1)个环节选到的元素重复,要减(N-1)。 )

上代码:

#include<iostream>
using namespace std;
int main(){
long long N,a,ans=1,Maxnumber[1001]={0},s=0;
cin>>N;
for(int i=0;i<N;i++){
cin>>a;
Maxnumber[a]++;
}//桶排序
for(int i=0;i<1001;i++){
if(Maxnumber[i]){/*等价于if(Maxnumber[i]!=0)*/
if(i-s<=0){
cout<<0;
return 0;
//不符合由乘法原理得出的结论,不可能实现。输出"0",结束程序
}
else{
while(Maxnumber[i]!=0){
ans=(ans*(i-s))%1000000007;
s++;
Maxnumber[i]--;
}
}
if(s==N){
break;
//所有元素已遍历,跳出循环
}
}
}
cout<<ans;
return 0;
}

原文地址:https://www.cnblogs.com/samuelx/p/12849953.html