zoukankan      html  css  js  c++  java
  • hdu 5976 Detachment 逆元的应用

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5976

    题目要求将一个数n分解成若干个不同的整数,使得他们的乘积最大,我们知道,任何数x想要分解成n个数使得乘积最大就要将每个数变成x/n,如果不限制数的数量就尽可能多的分成三,剩下的分成二,如果要求数不能相同的话就要尽量将数分成连续的整数段。

    按照以往经验,必然是取一段连续自然数能够使得乘积最大,而这段连续自然数可从2开始(为啥不从1开始?从1开始还不如将这个1给这段连续自然数的最后一个数),于是我们可以得到形如2+3+4+...+k(k=2,3,...)的式子,而x是10^9内的任意整数,我们不可能恰好能够凑成连续自然数之和,可能会多出△x

    而这个△x的值,我可以保证它的范围为0≤△x≤k,相信大于等于0还是好理解的,为什么会小于等于k呢?因为当它大于k时,原式不是可以增加一项?即2+3+4+...+k+(k+1)

    那么多出来的△x怎么处理呢?显然是从后往前均摊给连续自然数中的(k-1)个数,为啥从后往前?因为若我们从前往后,总是会使连续自然数重复,不好处理

    于是,在我们分配完△x之后,我们大致会得到下述两种式子:

    ①2*3*...*(i-1)*(i+1)*...*k*(k+1)

    ②3*4*...*i*(i+1)*...*k*(k+2)

    显然,我们要计算此结果,可以借助阶乘,而阶乘中缺失的项,我们除掉就可以了,那么便会涉及除法取模,显然需要用到乘法逆元

    代码如下:其中求逆元用的是费马小定理

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef unsigned int ui;
     4 typedef long long ll;
     5 typedef unsigned long long ull;
     6 #define pf printf
     7 #define mem(a,b) memset(a,b,sizeof(a))
     8 #define prime1 1e9+7
     9 #define prime2 1e9+9
    10 #define pi 3.14159265
    11 #define lson l,mid,rt<<1
    12 #define rson mid+1,r,rt<<1|1
    13 #define scand(x) scanf("%llf",&x) 
    14 #define f(i,a,b) for(int i=a;i<=b;i++)
    15 #define scan(a) scanf("%d",&a)
    16 #define mp(a,b) make_pair((a),(b))
    17 #define P pair<int,int>
    18 #define dbg(args) cout<<#args<<":"<<args<<endl;
    19 #define inf 0x7ffffff
    20 inline int read(){
    21     int ans=0,w=1;
    22     char ch=getchar();
    23     while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
    24     while(isdigit(ch))ans=(ans<<3)+(ans<<1)+ch-'0',ch=getchar();
    25     return ans*w;
    26 }
    27 int n,m,t;
    28 const int maxn=1e5+10;
    29 const ll mod = 1e9+7;
    30 ll sum[maxn],mul[maxn]; 
    31 int top=0;
    32 ll inv(ll a ,int k)//费马小定理在O(logn)时间内求解逆元  
    33 {
    34     ll ans= 1;
    35     while(k)
    36     {
    37         if(k&1)ans=(ans*a)%mod;
    38         k>>=1;
    39         a=(a*a)%mod;
    40     }
    41     return ans;
    42 }
    43 void init()//处理前缀和以及前缀积 
    44 {
    45     sum[1]=1;
    46     mul[1]=1;
    47     top=1;
    48     ll num=0,mu=1,i=2;
    49     while(num<=1000000000)
    50     {
    51         num=num+i;
    52         sum[++top]=num;//从2开始累加 
    53         mu=mu*i%mod;
    54         mul[top]=mu;
    55         i++;
    56     }
    57 }
    58 int main()
    59 {
    60     //freopen("input.txt","r",stdin);
    61     //freopen("output.txt","w",stdout);
    62     std::ios::sync_with_stdio(false);
    63     init();
    64     t=read();
    65     while(t--)
    66     {
    67         n=read();
    68         if(n==1)
    69         {
    70             pf("1
    ");
    71             continue;
    72         }
    73         ll ans=0; 
    74         //查找最后一个小于等于n的位置
    75         int k=upper_bound(sum+1,sum+top+1,n)-sum-1;
    76         int s=n-sum[k];//剩余的数 
    77         if(s==k)//此时是 3*4...(k+1)*(k+2)形式 
    78         {
    79             ans=(mul[k]*inv(2,mod-2)%mod*(k+2))%mod;
    80          }
    81          else //此时是2*3*...*(i-1)*(i+1)*...*(k+1) 
    82          {
    83              ans=(mul[k+1]*inv(mul[k-s+1],mod-2)%mod*mul[k-s])%mod;
    84           } 
    85         pf("%lld
    ",ans);
    86     }
    87 } 
  • 相关阅读:
    linux 下的文件IO基础
    git命令-切换分支
    专利搜索引擎
    在此位置打开CMD
    2017 JAVA神器 Btrace详细介绍
    linux下的find文件查找命令与grep文件内容查找命令
    Linux如何查看JDK的安装路径
    JavaScript SetInterval与setTimeout使用方法详解
    ssh 登录出现Are you sure you want to continue connecting (yes/no)?解决方法
    ssh连接提示 "Connection closed by remote host"
  • 原文地址:https://www.cnblogs.com/randy-lo/p/12750478.html
Copyright © 2011-2022 走看看