1. 程式人生 > >2016年ACM/ICPC大連賽區重現賽 F題

2016年ACM/ICPC大連賽區重現賽 F題

本題簡單明瞭

給你 T 組資料,然後輸入 n ,把n拆解成不同的數字,使這些數字相乘最大。

。。。

這種簡單題往往最噁心。。

首先我們想一下,如果把一個數拆分成任意的數字相乘,最大的肯定是 2*2*2*2*2*。。。。到最後剩下奇數就*3,但是這道題是不同的數字,就往儘可能 小數多乘。這種思路走。。

 

那麼這道題就顯而易見了

拆解成 2+3+4+5+......+x , 假設 設此時 和為 Sn

那麼有以下幾種情況

Sn == n 輸出  x! 完美解決

Sn == n+1 那麼 我們捨棄 2 留下 x+1 就好了

如果 Sn > n + 1 那麼 Sn - n = k 捨棄掉 k ,留下 x+k-1 就解決了。。

但是問題關鍵來了。。。當初自己天真的去解決這個問題時候,發現如果加入取模運算,就沒那麼簡單了,階乘的話進行一下打表處理就可以了,但是這道題 需要一下逆元處理。。。這就有些超出理解認知了。。。還需要學習啊。。。

但是看了看大犇們的部落格。。。發現自己思路一樣以外。。。逆元根本不懂。。

以下摘錄自一個大犇的部落格:http://www.cnblogs.com/Judge/p/9383034.html

所以逆元是什麼東西呢? 首先這裡有個式子: (a/b) %p ,這個式子的答案怎麼求? 
沒錯,暴力求是一種方法,但是當 b 非常大的時候呢 ? 這個時候就要用到逆元了。--來自網路上大犇的部落格

我們不能直接說一個數的逆元是多少, 
應該這麼說: 一個數 x 在模 p 的條件下的逆元是多少

其次,我們不難得知一個數的逆元有多個,但是我們只需要求得一個數的最小正整數逆元就行了

考慮到這道題數比較大,所以需要逆元處理 那麼 除以一個數再取模等同於乘以這個數的逆元再取模。。

 

只能膜拜大犇了。。。這次又學習了逆元,也算有收穫了。

 

 

 

 

下邊是個 AC 程式碼。。我盡力的去搞一下逆元吧。。(注意HDU 上提交用 G++ C++超時。。。)

#include<iostream>
#include<cstdio>
using namespace std;
#define ll long long int
const ll mod = 1e9 + 7;
const ll maxn = 100010;
ll n;
ll temp,ant;
bool jud(ll x)
{
    return ((x*(x+1)/2-1)>=n);
}
ll pow_(ll x,ll n)
{
    ll ans = 1;
    x=x%mod;
    while(n)
    {
        if(n&1)
            ans=ans*x%mod;
        x=x*x%mod;
        n>>=1;
    }
    return ans;
}
ll jie[maxn];
int main()
{
    jie[0]=1;
    for(int i=1;i<maxn;i++)
        jie[i]=(jie[i-1]*i)%mod;
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lld",&n);
        if(n<=4)
        {
            printf("%lld\n",n);
            continue;
        }
        ll l=0,r=n,mid;
        while(l<r)
        {
            mid = (l+r)>>1;
            if(jud(mid))
              r=mid;
            else
              l=mid+1;
        }
        l=r;
        ant = 1;
        temp = (r*(r+1)/2-1);
        if(temp==n)
        {
            printf("%lld\n",jie[l]);
            continue;
        }
        l--;
        if(temp == n+1)
        {

            ant=jie[l];
            ant=ant*pow_(2,mod-2)%mod;
            ant=(ant*(l+2))%mod;
            printf("%lld\n",ant);
        }
        else
        {
            ant=jie[l+1];
            ant=ant*pow_(temp-n,mod-2)%mod;
            printf("%lld\n",ant);
        }
    }
    return 0;
}