傳送門
題意:給定乙個數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
#include
#include
using
namespace
std;
const
int mod=1e9+7;
long
long db[100001],db2[100001];
long
long quick_mod(long
long a,long
long b)
return ret;
}int main()
scanf("%d",&w);
while (w--)
r=lower_bound(db2,db2+100000,n)-db2;
if (db2[r]==n)
else
if(db2[r]-n==1)
n=n-db2[r-1];
k=r-n;
ans=db[r]*quick_mod(k,mod-2)%mod;
printf("%lld\n",ans);
}return
0;}
HDU5976 貪心 逆元 字首和
大連區域賽的銅牌題,雖然只是銅牌題我也想了好一會,感覺這場區域賽挺不好打呀。貪心策略我是這樣想出來的,先令n 25把,寫成34567乘積最大,假如n被迫變小呢?34567 24567 23567 23467 23456,這樣最划算對吧,那麼接下來?23456 3457,因為長度被迫 1了,and t...
HDU 5976 逆元,字首和,數論
一些總結 1 乙個數字若是分成任意數字求乘積和最大,則盡量全部分成3 2 分成兩個則是n 2 3 拆成n個,拆成這個數 n 4 不能重複,則優先拆為2,3,4 剩餘 x從後往前平分。逆元應用 求逆元 inv 1 1 1的逆元顯然是1 for i 2 i include define max 1000...
HDU 4857逃生(逆拓撲排序)
糟糕的事情發生啦,現在大家都忙著逃命。但是逃命的通道很窄,大家只能排成一行。現在有n個人,從1標號到n。同時有一些奇怪的約束條件,每個都形如 a必須在b之前。同時,社會是不平等的,這些人有的窮有的富。1號最富,2號第二富,以此類推。有錢人就賄賂負責人,所以他們有一些好處。負責人現在可以安排大家排隊的...