题目大意
给定一个数,让你分成互不相等的n个数(n为自然数),使这些数的乘积最大,输出最大乘积。
题目分析
我也不知道数论的一些东西怎么证明,但是拿到一个数的时候分配,肯定是要分配到的数越小越好,但是不能分配出1,因为分配出1相乘之后得到的结果不会增加,因为想法就是枚举2,3,4,5……知道不能枚举即可。这个可以预处理一下,当然肯定还有未分配完的数,这时候要分情况讨论:
情况1:枚举l,并且剩余的数等于l,这时候应该得到的结果是 3∗4∗5∗6∗7∗....∗l∗l+2
情况2:枚举l,并且剩余的数小于l,这时候应该得到的值是 2∗3∗4∗5∗....∗k−1∗k+l∗......∗l−1∗l∗l+1
情况3:枚举l,并且剩余的数等于0,这时候应该得到的值是$2*3*4*…*l-1*l
这样大部分都完成了,但是需要用逆元只是处理,因为我们预处理mul[i]表示2乘到l的值,处理某些值的时候需要逆元。。。。简单处理一下即可。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define LL long long
const int maxn = 1e5;
const LL mod = 1e9+7;
LL add[maxn], mul[maxn];
void exgcd(LL a, LL b, LL& d, LL& x, LL& y){ //扩展欧几里得
if(!b){ d = a; x = 1; y = 0;}
else{
exgcd(b, a%b, d, y, x);
y -= x*(a/b);
}
}
LL inv(LL a, LL n){ //求逆元
LL d, x, y;
exgcd(a, n, d, x, y);
return (x+n)%n;
}
void init(){
memset(add, 0, sizeof(add));
memset(mul, 0, sizeof(mul));
add[0] = add[1] = 1;
add[2] = 2;
mul[0] = mul[1] = 1;
mul[2] = 2;
for(LL i = 3; i < maxn; i++){
add[i] = add[i-1]+i;
mul[i] = (mul[i-1]*i)%mod;
}
}
int main(){
init();
LL T, x;
scanf("%I64d", &T);
while(T--){
scanf("%I64d", &x);
if(x <= 4){
printf("%I64d\n", x);
continue;
}
int l = 2, r = maxn-5;
while(l < r){
int mid = (l+r+1)/2;
if(add[mid] <= x) l = mid;
else r = mid-1;
}
LL temp = x - add[l];
if(temp == l) printf("%I64d\n", mul[l]*inv(2, mod)%mod*(l+2)%mod);
else if(temp == 0) printf("%I64d\n", mul[l]);
else printf("%I64d\n", mul[l-temp]*mul[l+1]%mod*inv(mul[l-temp+1], mod)%mod);
}
return 0;
}