1011: QAQ的序列组合
时间限制: 1 Sec 内存限制: 128 MB
提交: 112 解决: 17
[提交][状态][讨论版]
题目描述
QAQ有1−N
共N个不同的整数,已知第i个整数有a[i]
个。
现在QAQ想知道一共有多少种不同的组合方案。
输入
第一行输入一个整数T
,代表有T组测试数据。
每组数据占两行,第一行输入一个整数N,代表N个不同的整数。
接下来输入N个整数a[]。
注:1<=T<=30,1<=N<=10000,0<=a[]<=100
。
输出
对每组测试数据,输出一个整数代表不同的组合方案。
由于结果可能会很大,请对(109+7)
取余。
如果所有整数的个数之和为0
,我们认为不存在合法的方案。
样例输入
2
3
1 1 1
3
1 1 2
样例输出
6
12
提示
对于第二组测试数据,有1 2 3 3共4个整数。
不同组合的方案有:
(1 2 3 3)、(1 3 2 3)、(1 3 3 2)、(2 1 3 3)、(2 3 1 3)、(2 3 3 1)、
(3 1 2 3)、(3 2 1 3)、(3 1 3 2)、(3 2 3 1)、(3 3 1 2)、(3 3 2 1)、
共12种。
记pa[i]是i元素出现的次数。
然后枚举每一个状态,共有(1<<10)−1共1023种状态。
对于状态S而言,若出现N个元素,那么它们的组合方案就是
cnt=(2^(pa[i]−1))∗(2^(pa[i+1]−1))∗…∗(2^(pa[N]−1))。
状态S的贡献就是出现的不同元素和sum 乘上 组合方案cnt。
我们累加贡献即可。
如果爆int,要这样写1 LL << x。
时间复杂度O(T∗1023∗10)。
AC代码 :
#include<cstdio>
const long long mod = 1e9 + 7;
int pa[10010];
long long jc[1000011];
long long KSM(long long x,long long y)
{
long long cut = x % mod;
long long sum = 1;
while(y){
if(y & 1)
sum = sum * cut % mod;
cut = cut * cut % mod;
y /= 2;
}
return sum;
}
int main()
{
int T,N,i,a;
long long ans;
jc[0] = 1;
for(i = 1 ; i <= 1000011 ; i++)
jc[i] = jc[i - 1] * i % mod;
scanf("%d",&T);
while(T--){
ans = 0;
scanf("%d",&N);
for(i = 1 ; i <= N ; i++){
scanf("%d",&pa[i]);
ans += pa[i];
}
if(ans == 0)
printf("0\n");
else{
ans = jc[ans];
for(i = 1 ; i <= N ; i++){
a = pa[i];
if(a)
ans = ans * KSM(jc[a] , mod - 2) % mod;
}
printf("%lld\n",ans);
}
}
return 0;
}