[HDU4390]表达式计数
时间限制: 1 Sec 内存限制: 128 MB题目描述
输入
输出
对于每组测试数据,输出有多少种数列满足情况,结果对1e9+7取余
样例输入
2
3 4
样例输出
4
数据规模太大,所以只能考虑将b1*b2*....*bn分解质因数,由唯一分解定理可得,对于该数列的乘积,只有一种分解方式,即每种质因子的个数都是一定的。
对乘积分解质因子得 a[i] 表示第 i 种质因子的个数
问题可以转化成:
现有i种不同颜色的小球,每种小球有a[i]个,还有N个不同的盒子,求将所有小球装进N个盒子的方案数,盒子不能为空( i从0开始算 )
数列顺序可交换,所以对应的盒子是不相同的
如{1,2} {2,1}是两个数列
对于第i种小球,可以看做是将a[i]个相同的小球放进N个不同的盒子中,盒子可以为空(稍后解释)
此时方案数为C[ a[i] + N - 1, N - 1 ],证明如下:(即第二类Stirling的证明)
设每个盒子中装的小球数量为Xj,Xj>=0,则是求此方程的解有多少组
X1+X2+X3+....+Xn = a[i]
X1+X2+X3+....+Xn + N = a[i] + N
此时就变成了a[i]+N个小球放进N个不同盒子中,每个盒子至少装一个
使用隔板法:
在这些小球中共有a[i]+N-1个空位可以放置隔板,放置N - 1个隔板即将它们分成N组(N盒)
从a[i]+N-1个位置中选择N - 1个位置的方案数为C[ a[i]+N-1 , N-1 ]
对于一种颜色小球的一种方案,其他小球的每一种方案都可以与之相适应,所以此时i种小球的总方案数为∑C[ a[i]+ N-1 , N-1 ] (0<=i<=cnt)
但是这里有个很明显的bug,在第i种小球的方案中,有很多是有空盒子的,这本来是必须的(因为新数列中的数并不是每个数都要含有乘积中的每个质因子)
当i种小球放在一起,就会出现空盒子(一种小球都没有),这样的情况还有很多,空盒子为0~N-1个
所以要去重复
有容斥原理:A1类元素A2类元素A3类元素....An类元素个数总和=∑Ai (1<=i<=N) - ∑既是Ai类又是Aj类元素个数总和(1<=i<=j<=N) + ∑既是Ai类又是Aj类又是Ak类元素个数总和(1<=i<=j<=k<=N) - .... + [(-1)^(N-1)]*(既是A1又是A2又是A3....又是An类元素个数总和)
在此题中,Ai类指∑第 j 种颜色的小球,空了i个盒子的方案数(即 将a[j]个相同小球放进N-i-1个盒子中的方案数) 1<=i<N , 0<=j<=cnt
如:
A1类指∑第j种颜色小球空了1个盒子,即放置在N-1个盒子中C[a[j]+N-1, N-1-1],1<=i<N , 0<=j<=cnt
A2类指∑第j种颜色小球空了2个盒子,即放置在N-2个盒子中C[a[j]+N-1, N-1-2],1<=i<N , 0<=j<=cnt
....
Acnt类指∑第j种颜色小球空了n-1个盒子,即放置在1个盒子中C[a[j]+N-1, 0],1<=i<N , 0<=j<=cnt
最后的答案即是:总方案数-有空盒的方案数
Code:
Status | Accepted |
---|---|
Memory | 3680kB |
Length | 1430 |
Lang | G++ |
Submitted | 2017-07-08 20:11:28 |
Shared | |
RemoteRunId | 21030727 |
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<vector>
using namespace std;
typedef long long LL;
const int MOD = 1e9 + 7;
int N;
LL Ans;
int a[1005];
LL C[505][505];
vector<int>P;
void pre_work(){
C[0][0] = 1;
for(int i = 1; i <= 500; ++ i){
C[i][0] = C[i][i] = 1;
for(int j = 1; j < i; ++ j)
C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % MOD;
}
}
void solve(int cnt){//将格子是否放置质因数进行容斥
Ans = 1LL;//因为直接根据每种质因子分进N个格子的方案中,直接相乘会造成有的格子里一个质因子也没有,而题目要求ai > 1,所以不能有格子被空着不放
for(int i = 0; i <= cnt; ++ i)
Ans = (Ans * C[a[i] + N - 1][N - 1]) % MOD;//每种质因子被无限制条件地分进N个格子中的方案数(可以放,可以不放)
for(int i = 1; i < N; ++ i){//N个格子的加减容斥
LL tmp = C[N][i];//N个格子中有i个格子空着不放的方案数
for(int j = 0; j <= cnt; ++ j)//第j种质因子放入剩下的N - i个格子中的方案数
tmp = (tmp * C[N + a[j] - i - 1][N - i - 1]) % MOD;
if(i & 1) Ans = ((Ans - tmp) % MOD + MOD) % MOD;
else Ans = (Ans + tmp) % MOD;
}
}
int main(){
pre_work();
int x;
while(~scanf("%d", &N)){
for(int i = 1; i <= N; ++ i){
scanf("%d", &x);
for(int j = 2; j * j <= x; ++ j)
while(x % j == 0)
x /= j, P.push_back(j);
if(x > 1) P.push_back(x);
}
sort(P.begin(), P.end());
int cnt = 0, len = P.size();
a[0] = 1;
for(int i = 1; i < len; ++ i)
if(P[i] == P[i - 1]) ++ a[cnt];
else a[++ cnt] = 1;
solve(cnt);//一共有cnt种质因子
printf("%lld\n", Ans);
memset(a, 0, sizeof(a));
P.clear();
}
return 0;
}