hdu5976 Detachment 逆元 优化

本文探讨了如何将一个整数分解成若干个尽可能小且互不相同的数字之和,以使这些数字的乘积最大。通过分析得出,应当尽量使用较小的数字进行分解,并保持这些数字间的差距最小。此外,还提供了具体的算法实现,包括前缀积预处理和二分查找优化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门
题意:给定一个数x,我们可以把这个数分解成一个一个的小的数字a1,a2,a3……
定义s=a1*a2*a3*…….
问如何分解x使得s最大,并且不能有重复的数字
思路:分解成数量多的小的数字,比分解成数量少的大的数字的乘积更大,这一点我不知道怎么证明……并且由基本不等式我们可以知道,相等和的两个数,越接近那么乘积越大
可想而知,如果可以有重复的数字,那我们可以把x分解成2和3的和即可,本题要求不能有重复的数字,原则是分解成更多小的数、更接近的数字,那么就可以2+3+4+…,但一般来说都不能正好分解完,会剩余一个数字,比如11=2+3+4+2,剩余了一个2,那我们把这个剩余的数字加到哪比较好呢,第一反应是直接加到最大的数字上,但仔细想想这样的话会扩大最后一个数与倒数第二个数的差,乘积可能会相对来说减少,所以我们要把这个数补在某个数上,使得补完后这个数接近之前的数群,比如11来说,我们把2补在3上,就变成了11=2+4+5,这样的乘积是比11=2+3+6的乘积大
如果我们定义可以分解成的最大的那个数为r,剩余的那个数为m,那么仔细想想就可以发现我们每次都可以把m补成r+1,除非m与r相等(因为前面没有1)
m=r的情况特判
m=r+1的情况也特判一下
其他情况就是r+1的前缀积除掉r+1-m,由于结果要对1e9+7取模,所以就是乘上r+1-m的逆元
两个需要优化的地方:前缀积要预处理一下,在找r时,用二分优化,求2,3,4……这个序列的前缀和,然后找x的位置,这里用了lower_bound函数

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MOD=1e9+7;
long long db[100001],db2[100001];
long long quick_mod(long long a,long long b)
{
    long long ret=1;
    while (b)
    {
        if (b&1)
            ret=(ret*a)%MOD;
        a=a*a%MOD;
        b>>=1;
    }
    return ret;
}
int main()
{
    int w;
    int n,a,b,k,r;
    long long ans;
    db[2]=db2[2]=2;
    for (int i=3;i<=100000;i++)
    {
        db[i]=(db[i-1]*i)%MOD;
        db2[i]=db2[i-1]+i;
    }
    scanf("%d",&w);
    while (w--)
    {
        scanf("%d",&n);
        if (n<=4)
        {
            printf("%d\n",n);
            continue;
        }
        r=lower_bound(db2,db2+100000,n)-db2;
        if (db2[r]==n)
        {
            printf("%lld\n",db[r]);
            continue;
        }
        else if(db2[r]-n==1)
        {
            ans=db[r-1]*quick_mod(2,MOD-2)%MOD;
            ans=ans*(r+1)%MOD;
            printf("%lld\n",ans);
            continue;
        }
        n=n-db2[r-1];
        k=r-n;
        ans=db[r]*quick_mod(k,MOD-2)%MOD;
        printf("%lld\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值