hdu5976 Detachment思维数学(贪心+逆元)

这个题,比赛的时候分析出来了,但是最后时间不够了,就没有做出来,GG了,最后补题的时候有因为自己地粗心开始不断debug,不过也发现问题了。
先来说一下思路,将这个数分解后使其乘积最大,且因子各不相同,我就想到了阶乘,但是一个数不一定可以分解的彻底,所以可以将其从后向前均分到每一个数上,可以想一下,前面的数每增加1其实就是相比于原乘积增加一倍的后面数的乘积。然后分析一下时间复杂度,发现必须直接计算,就考虑用阶乘预处理,然后因为可能分解过后的数不连续,就用阶乘 乘 缺的那个数的逆元。

#include
#include
#include
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;
}

你可能感兴趣的:(贪心只能过样例,数论)