• 寒假Day54:HDU5976Detachment前缀和+前缀积+逆元(费马小定理)+二分


    题目链接:

    http://acm.hdu.edu.cn/showproblem.php?pid=5976

    题意:

    把一个数拆成几个不相同的数,求这些数的乘积的最大值。

    思路:

    使一个数n乘积最大,拆成两个数x、y  --->  则x、y接近n/2,再去进行拆分;

    但是题意给的是不相同的多个数,所以最优解则是  --->  (2+3+...+k)=n,要是从2开始且连续的;

    所以我们开一个sum数组去处理一下前缀和;

    既然如此,那么如果找到了最优解,那么还会有剩下的数 ---> yu = n - sum [ k ],

    但是别忘了sum是从2开始存储的,所以预处理的时候需要sum [ 0 ] = sum [ 1 ] = 0;

    如何处理剩下的数yu呢?

    这个数应该加到2+3+...+k的其中一个数字上去,

    (这个道理我不知道为什么)给到最小的数字上面去乘积就是最大的,但是要保证加上最小的数字之后也不存在重复,

    所以给到的就是 ---> q = k + 1 - yu ,找q需要二分,因为数据比较大+是有序的

    所以ans =ji[k]/q*(q+yu) ---> ji:前缀积数组

    除法用逆元 ---> 费马小定理

    费马小定理模板:(就是在快速幂的基础上-2)

    ll pow_mod(ll a,ll b)//a的b次方对mod求余
    {
        ll res=1;
        while(b)
        {
            if(b&1)
                res=(res*a)%mod;
            a=(a*a)%mod;
            b>>=1;
        }
        return res;
    }
    
    
    ll Fermat(ll a,ll p) //费马小定理求a关于b的逆元
    {
        return pow_mod(a, p-2, p);
    }

    AC代码:

    #include<stdio.h>
    #include<iostream>
    #include<algorithm>
    #include<string.h>
    using namespace std;
    typedef long long ll;
    
    const int mod=1e9+7;
    const int N=1e5+10;
    ll sum[N],ji[N],num[N];
    int n,w;
    
    void init()
    {
        sum[0]=sum[1]=0;
        ji[0]=ji[1]=1;
        w=0;
        for(int i=2; ; i++)
        {
            num[w++]=i;
            sum[i]=sum[i-1]+i;//前缀和
            ji[i]=ji[i-1]*i%mod;//前缀积
            if(sum[i]>1e9)
                break;
        }
    }
    
    ll fm(ll a,ll b)
    {
        ll res=1;
        while(b)
        {
            if(b&1)
                res=res*a%mod;
            a=a*a%mod;
            b>>=1;
        }
        return res;
    }
    
    int main()
    {
        init();
        int t;
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d",&n);
            if (n==1)
            {
                printf("1\n");
                continue;
            }
            int k=(upper_bound(sum,sum+w+2,n)-sum)-1;
            int yu=n-sum[k];//n-sum(2+3+...+k)处理多出来的数yu
            int p=lower_bound(num,num+w,k+1-yu)-num;//多出来的数给到k+1-yu
            ll ans=(ji[k]%mod*fm(num[p],mod-2)%mod)%mod;
            ans=ans*(num[p]+yu)%mod;
            printf("%lld\n",ans);
        }
        return 0;
    }
  • 相关阅读:
    使用python3自带工具2to3.py 转换 python2.x 代码 到python3
    python2代码转换python3(2018新)
    解析搜狗词库(python)
    把搜狗输入法词库导入Google拼音输入法
    QT 窗体控件的透明度设置(三种方法)
    Telnet协议详解(远程登陆协议)
    C++游戏开发需要阅读的书籍
    explicit的作用
    C#7.0
    ES6-2
  • 原文地址:https://www.cnblogs.com/OFSHK/p/12513938.html
Copyright © 2020-2023  润新知