https://nanti.jisuanke.com/t/41412
题意:给定n,求满足下面关系的集合
a
a
a个数。
思路:容易想到,积增加的速度远快于和,那么n大一点时,就是【若干个数与若干个1相加】与【这些数相乘】相平衡。由于
2
12
=
4096
2^{12}=4096
212=4096,故非1的数最多11个,那么dfs枚举所有的组合加上剪枝即可。计算组合时,用了一点组合数学的技巧。比如1111111111223334这个,会多次枚举223334这6个数,因为
6
!
=
=
这
6
个
数
的
不
同
排
列
数
∗
3
!
∗
2
!
∗
1
!
6!==这6个数的不同排列数*3!*2!*1!
6!==这6个数的不同排列数∗3!∗2!∗1!,那么我们每次枚举到一个排列,都除去1的个数的阶乘,再除以6!(因为除以6!等价于除以(这6个数的不同排列数*3!*2!*1!),而这6个数的不同排列都会枚举到)。这样的话,
计
算
1
次
16
!
10
!
∗
3
!
∗
2
!
∗
1
!
就
等
效
成
计
算
6
!
3
!
∗
2
!
∗
1
!
次
16
!
10
!
∗
6
!
之
和
。
计算1次\frac{16!}{10!*3!*2!*1!}就等效成计算\frac{6!}{3!*2!*1!}次\frac{16!}{10!*6!}之和。
计算1次10!∗3!∗2!∗1!16!就等效成计算3!∗2!∗1!6!次10!∗6!16!之和。
#include<bits/stdc++.h>
using namespace std;
const int maxn=3005;
const int mod=1000000007;
typedef long long ll;
int T,n;
ll fac[maxn],inv[maxn],ans[maxn];
ll pow_mod(ll a,ll n)
{
if(!n)return 1;
ll x=pow_mod(a,n/2);
x=x*x%mod;
if(n&1)x=x*a%mod;
return x;
}
void init()
{
fac[0]=inv[0]=1;
for(int i=1;i<maxn;i++)fac[i]=fac[i-1]*i%mod,inv[i]=pow_mod(fac[i],mod-2);
}
void dfs(int depth,int sum,ll mul)
{
int n=mul-sum+depth;
if(n>3000)return;
ans[n]=(ans[n]+fac[n]*inv[n-depth]%mod*inv[depth]%mod)%mod;
for(int i=2;i<=6000/mul;i++)
{
dfs(depth+1,sum+i,mul*i);
}
}
int main()
{
//freopen("input.in","r",stdin);
init();
dfs(0,0,1);
cin>>T;
while(T--)
{
cin>>n;
cout<<ans[n]<<endl;
}
}