题意很简单:将一个整数n分解成很多不相同整数的和,使得这些整数乘积尽可能大。其中n最大1e9
第一眼看到这个题:
好简单啊,都分解成3啊!(没看到不相同)
第二眼:
可以猜想几个结论:
A:首先不可能有1,不要当作废话,那么意味着从2开始分解是有可能的
B:分解成尽可能多的数。个数多,比数大要好
举个例子:5=2+3,但是5如果不分解,答案是5;但是分解之后,5=2+3,答案为2*3=6
由这两个看似有道理的情况,说明我们要从2开始,不断往上加,来构造n:即:2+3+4+5+……
可惜的是:没有这么幸福的事,因为不相同,所以会有重复
比如7:7=2+3+2,剩下的这个2,怎么办:分解成1+1,往2+3上面分配就好:7=3+4
比如8:8=2+3+3,剩下的这个3,怎么办:分解成1+2,往2+3上面分配就好:8=3+5
所以,按照这个方法,我们猜想得到:这个题是一个构造题
为了方便自己计算,也为了方便最后编程之后得到更快的检验,我们先手算把简单的数字都算出来:
1=1
2=2
3=3
4=4
5=2+3
6=2+3+1=2+4
7=2+3+2=3+4
8=2+3+3=2+3+1+2=3+5
9=2+3+4
10=2+3+4+1=2+3+5
11=2+3+4+2=2+3+4+1+1=2+4+5
12=2+3+4+3=2+3+4+1+1+1=3+4+5
13=2+3+4+4=2+3+4+1+1+2=3+4+6
14=2+3+4+5
15=2+3+4+5+1=2+3+4+6
可以看到:分解数的个数是非递减的
意思是:我们可以根据输入的n,求出构造n的数位的长度len是多少
考虑到1+2+……+len是有公式的,我们可以算几个得到len
得到len之后,我们需要知道在1到len中少了哪几个数,多了哪几个外面的数
发现了几个规律:
当数字刚好是:2+3+……(len+1)的时候,刚好答案是(len+1)!
如果不是上面那种情况:那么只有两种情况:
A:缺1个数,可能缺2,3,4,等某一个
B:缺2个数,必然缺2,而且另一个是len
所以,我们把这些在的值乘起来就好
但是,这个题时限卡得很死
所以要用数学办法预处理好阶乘和逆元来搞
当答案跟len有关的时候,我们直接使用len的阶乘值
当要删去某个值的时候,我们直接乘那个数的逆元就好
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define LL __int64
int t;
LL jiecheng[100050];
LL niyuan[100050];
LL x,mod=1e9+7;
LL qp(LL x,LL p){
if (p==1) return x;
LL res=1;
while(p){
if (p%2) res=(res*x)%mod;
p/=2;
x=x*x%mod;
}
return res;
}
int main(){
//freopen("input.txt","r",stdin);
jiecheng[1]=1;
for(int i=2;i<=100000;i++)
jiecheng[i]=(jiecheng[i-1]*i)%mod;
for(int i=2;i<=100000;i++)
niyuan[i]=qp(1LL*i,mod-2);
scanf("%d",&t);
for(int Case=1;Case<=t;Case++){
scanf("%I64d",&x);
LL len,sum;
if (x<=4){
printf("%I64d\n",x);
continue;
}
else if (x==5){
puts("6");
continue;
}
//printf("%I64d: ",x);
len=(long long)(sqrt(2.0*x));
while((1+len+1)*(1+len)>2*(1+x)) len--;
//printf("%I64d %I64d\n",x,len);
len++;
sum=(1+len)*len/2;
if (sum==x+1) printf("%I64d\n",jiecheng[len]);
else{
sum+=len;len++;
if (sum==x+1){
//printf("%I64d %I64d\n",jiecheng[len+1],2*(len));
printf("%I64d\n",((jiecheng[len+1]*niyuan[2]%mod)*niyuan[len]%mod));
}
else{
printf("%I64d\n",jiecheng[len]*niyuan[sum-x]%mod);
}
}
}
return 0;
}