题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5976
题意:把一个数拆成若干个不相同的数之和,问这些数的乘积最大是多少。
思路:一般要使乘积最大,那么先拆成两个不同数时,这两个数一定是接近n/2,然后每一个数又可以拆成两个数。但要这些数都不相同,所以最好的情况肯定是n等于从2开始一直到某个数k的连续和,如9=2+3+4,这样肯定是最优的,那么n-sum(2+...+k)怎么处理呢?如11=2+3+4+2,还剩了个2,那么只能把这个数分配给它们其中的一个,首先,肯定是分给越小的数越好,这样提升乘积更大,而且还不能重复,就只能给(k+1)-多出来的数,11的话就是给到3,这里要二分来找,最后的答案就是2到k的乘积除以给到的数再乘以给到的数加多出来的数,这里除以要用到逆元,乘积和sum都可以前缀和预处理出来。
代码:
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define eps 1e-7
#define fuck(x) cout<<"<"<<x<<">"<<endl
#define fi first
#define se second
#define pb push_back
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const double PI = acos(-1.0);
const LL INFLL = 0x3f3f3f3f3f3f3f3fll;
const int maxn = 1e5 + 5;
const int mod = 1e9 + 7;
int t,n;
LL sum[maxn];
LL ji[maxn];
int num[maxn],cnt;
LL qp(LL a,LL b){
LL ans=1;
while (b){
if (b&1) ans=(ans*a)%mod;
a=(a*a)%mod;
b>>=1;
}
return ans;
}
int main() {
sum[0]=sum[1]=0;
ji[0]=ji[1]=1;
cnt=0;
for (int i=2;i<=maxn;i++){
num[cnt++]=i;
sum[i]=sum[i-1]+i;
ji[i]=ji[i-1]*i%mod;
if (sum[i]>1e9) break;
}
scanf ("%d",&t);
while (t--){
scanf ("%d",&n);
if (n==1) {printf ("1\n");continue;}
int i=upper_bound(sum,sum+cnt+2,n)-sum;
i--;
int tmp=n-sum[i];
int pos=lower_bound(num,num+cnt,i+1-tmp)-num;
LL x=(LL)num[pos];
LL ans=(ji[i]%mod*qp(x,mod-2)%mod)%mod;
ans=ans*(x+tmp)%mod;
printf ("%lld\n",ans);
}
return 0;
}