hdu 5976 Detachment 逆元+二分+数学

来源:互联网 发布:美国歌手prince 知乎 编辑:程序博客网 时间:2024/05/01 14:29

给定一个数,让你分成互不相等的n个数(n为自然数),使这些数的乘积最大,输出最大乘积。

因为分的数不能相同,所以发现分的数越小越好,从2开始枚举分成2,3,4,5......

x=2+3+4+....+n+s(会剩下一个s)

枚举s三种情况

1.s==0

2.s==n

3.s<n

需要预处理,

add2到n个相加

mul2到n个相乘

处理某些值的时候要用逆元,求逆元不能超时。。

1到n的逆元,求解递推公式//o(n)求逆元,mod为素数
inv[1]=1;
for(int i=2;i<maxn;i++)
     inv[i]=(mod-mod/i)*inv[mod%i]%mod


#include <iostream>#include <cstring>#include <algorithm>#include <cstdio>using namespace std;#define LL long longconst int maxn=1e5;const LL mod=1e9+7;LL add[maxn],mul[maxn],inv[maxn];void init(){    memset(add,0,sizeof(add));    memset(mul,0,sizeof(mul));    add[1]=0;    mul[1]=1;    inv[1]=1;    for(int i=2;i<maxn;i++)    {        add[i]=add[i-1]+i;        mul[i]=(mul[i-1]*i)%mod;        inv[i]=(mod-mod/i)*inv[mod%i]%mod;    }}int main(){   LL Tcase,x;     init();   scanf("%I64d",&Tcase);    while(Tcase--)    {        scanf("%I64d",&x);        if(x<5)        {            cout<<x<<endl;            continue;        }       LL ii=upper_bound(add,add+maxn-1,x)-add;//stl的二分        ii--;       // cout<<ans;       LL s=x-add[ii];       LL ans;       if(s==0)        ans=mul[ii];        else if(s==ii)        ans=mul[ii]*inv[2]%mod*(ii+2)%mod;        else {            ans=mul[ii+1]*inv[ii+1-s]%mod;        }        cout<<ans<<endl;    }    return 0;}
用exgcd求逆元
//LL exgcd(LL a,LL b,LL &x,LL &y)//{//    if(b==0)//    {//        x=1;//        y=0;//        return a;//    }//    LL r=exgcd(b,a%b,x,y);//    LL t=x;//    x=y;//    y=t-a/b*y;//    return r;//}//LL inv(LL a, LL m){   //求逆元//    LL gcd, x, y;//    gcd=exgcd(a, m, x, y);//    return (x%m+m)%m;//}


0 0