//https://acm.hdu.edu.cn/showproblem.php?pid=5976
//题意:将一个数拆分成任意个不同的数,使得拆分出的数的积最大,输出积mod1e9+7
//数学思维+乘法逆元+前缀和预处理
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll MOD=1e9+7;
//第二版,需要优化查找x由哪些连续的数组成,以及连续数的乘积问题
//查找:可以预处理连续数的和,直接查找x在多少个数的和之间
//乘积:(参考网上做法)将连续的数的乘积视为阶乘,预处理出2到x^0.5的阶乘,如果不能连续则,算出不连续的那个数的逆元乘完取模
ll add[100005],mul[100005];
void init(){
add[1]=0;
for(int i=2;i<100000;i++){
add[i]=add[i-1]+i;
}
mul[1]=1;
for(int i=2;i<100000;i++){
mul[i]=(mul[i-1]*i)%MOD;
}
}
ll exgcd( ll a , ll b , ll &x , ll &y )
{
if( !b ) // 当 b =0 时
{
x=1,y=0;
return a;
}
// 当 b!=0 时
ll d=exgcd( b, a%b, x, y );
ll t=x;
x=y;
y=t-(a/b)*y;
return d;
}
/* 求逆元 a , m */
ll Inv_a(ll a,ll m)
{
ll x,y;
ll d=exgcd(a,m,x,y);
if(d==1)
{
return ( x%m + m )%m; // 保证逆元为正数
}
else
return -1; // ax+my=1 不成立,即 a ,m 不互质,无解
}
int main(){
init();
int t;
scanf("%d",&t);
while(t--){
ll x;
scanf("%lld",&x);
if(x>4){
int n=upper_bound(add+1,add+100000,x)-add;
n--;
//printf("%lld",mul[n]);
//printf("n=%d\n",n);
ll temp=x-add[n];
if(temp==0){
printf("%lld\n",mul[n]);
}
else if(n==temp){
printf("%lld\n",(mul[n]%MOD*Inv_a(2,MOD)%MOD*(n+2)%MOD)%MOD);
}
else{
printf("%lld\n",(mul[n+1]*Inv_a(n-temp+1,MOD)%MOD));
}
// int pos=upper_bound(add,add+50000,x)-add-1;
// int num=x-add[pos];
// long long x,y,ans;
// if(num==pos)
// {
// ans=(mul[pos]%MOD*Inv_a(2,MOD)%MOD*(pos+2)%MOD)%MOD;
// }
// else if(num==0)
// ans=mul[pos];
// else
// {
// ans=(mul[pos+1]%MOD*Inv_a(mul[pos-num+1],MOD)%MOD*mul[pos-num]%MOD)%MOD;
// }
// printf("%lld\n",ans);
}
else{
printf("%lld\n",x);
}
}
}
//注意点:取模时只要两个相乘就要再次取模
//第一版,复杂度为2*(x^0.5)*t,约为1e10,两秒明显超时
//明显分解一个数使乘积最大,且分解出的数不能相等,最好为从2开始的连续一串数(分析总结规律知,当不能刚好连续,最优为依次向大的数中加一)
//朴素做法,直接模拟,先分解x,再依次相乘
// int main(){
// int t,ans;
// scanf("%d",&t);
// while(t--){//复杂度为1e6
// int x,a[100005];
// ll ans=1;
// scanf("%lld",&x);
// int k=0;
// for(int i=2;i<x;i++){//相当于把x拆为连续的数的和,复杂度接近x^0.5
// a[++k]=i;
// x-=i;
// }
// int temp=k;
// for(;x>0;x--){
// a[temp--]++;
// if(temp<1) temp=k;
// }
// for(int i=1;i<=k;i++){//复杂度也为x^0.5
// ans=(ans*a[i])%MOD;
// }
// printf("%lld\n",ans);
// }
// return 0;
// }
HDU 5976 [数学]
最新推荐文章于 2024-06-11 11:00:55 发布