HDU - 5976 Detachment(贪心思维)

题目链接: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;
}

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值