hdu5976 Detachment思維數學(貪心+逆元)

這個題,比賽的時候分析出來了,但是最後時間不夠了,就沒有做出來,GG了,最後補題的時候有因爲自己地粗心開始不斷debug,不過也發現問題了。
先來說一下思路,將這個數分解後使其乘積最大,且因子各不相同,我就想到了階乘,但是一個數不一定可以分解的徹底,所以可以將其從後向前均分到每一個數上,可以想一下,前面的數每增加1其實就是相比於原乘積增加一倍的後面數的乘積。然後分析一下時間複雜度,發現必須直接計算,就考慮用階乘預處理,然後因爲可能分解過後的數不連續,就用階乘 乘 缺的那個數的逆元。

#include<cstdio>
#include<iostream>
#include<cmath>
using namespace std;
typedef long long LL;
const int MAXN = 1e6;
LL fa[MAXN + 10];
const LL mod = 1e9 + 7;
void pre()
{
    fa[1] = 1;
    for(int i = 2;i <= MAXN;++i)
        fa[i] = (fa[i - 1] * i) % mod;
}
LL quick_pow(LL a,LL b)
{
    LL ans = 1;
    while(b)
    {
        if(b&1) ans = (ans * a) % mod;
        a = (a * a) % mod;
        b>>=1;
    }
    return ans;
}
LL inv(LL n)
{
    return quick_pow(n,mod - 2);
}
int main()
{
    int T;
    scanf("%d",&T);
    pre();
    while(T--)
    {
        LL n;
        scanf("%lld",&n);
        if(n <= 4)
        {
            printf("%d\n",n);
            continue;
        }
        LL l = 2;
        LL r = ( sqrt( 1 + 8 * n) - 1) / 2.0;
        //cout << r << endl;
        LL yu = n - (LL)((r) / 2.0 * (r + 1) - 1);
        if( yu >= r + 1) yu -= r + 1,r++;
        LL len = r - l + 1;
        l += yu / len; r+= yu / len;
        yu %= len;
        LL m = r - yu;
        if(yu) r = r + 1;
        LL k1 = (fa[m] * inv(fa[l - 1])) % mod;
        LL k2 = yu > 0 ? (fa[r] * inv(fa[m + 1])) % mod : 1;
        LL ans = (k1 * k2) % mod;
        printf("%d\n",ans);
    }
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章