HDU 5976 Detachment

Detachment

Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1777 Accepted Submission(s): 495

Problem Description
In a highly developed alien society, the habitats are almost infinite dimensional space.
In the history of this planet,there is an old puzzle.
You have a line segment with x units’ length representing one dimension.The line segment can be split into a number of small line segments: a1,a2, … (x= a1+a2+…) assigned to different dimensions. And then, the multidimensional space has been established. Now there are two requirements for this space:
1.Two different small line segments cannot be equal ( ai≠aj when i≠j).
2.Make this multidimensional space size s as large as possible (s= a1∗a2*…).Note that it allows to keep one dimension.That’s to say, the number of ai can be only one.
Now can you solve this question and find the maximum size of the space?(For the final number is too large,your answer will be modulo 10^9+7)

Input
The first line is an integer T,meaning the number of test cases.
Then T lines follow. Each line contains one integer x.
1≤T≤10^6, 1≤x≤10^9

Output
Maximum s you can get modulo 10^9+7. Note that we wants to be greatest product before modulo 10^9+7.

Sample Input
1
4

Sample Output
4

Source
2016ACM/ICPC亚洲区大连站-重现赛(感谢大连海事大学)


题意:
16年大连区域赛的题,听说六道题慢的都打铁了啊QAQ,太可怕了。这题写不出的都没有铜。。
题意给你一个整数,把它拆成几个不相等的整数,求这些拆出的整数的积的最大值。

思路:
一开始就非常懵逼啊,因为数小的时候基本上就是这个数的一半的平方左右,然后怒WA了,后来想想还是太天真了,然后认认真真手推了14个数:

n个数拆出的数
1111
2122
3133
4144
522 36
622 48
723 412
823 515
932 3 424
1032 3 530
1132 4 540
1233 4 560
1333 4 672
1442 3 4 5120

然后我突然悟到了规律,就是总要拆成几个尽可能小的不同数。然后打个表,二分找下需要拆成几个数,接下来就是找出这几个数。
拿拆成 3 个数的 9~13 来说。除了13比较特殊,结果是 (1+k)!/2*(3+k) 以外,其他的数都是 (2+k)!/(2+k-x) 。其中k是要拆成k个数,x=n-ss[k] 。

我一开始拿for循环写的,然后TLE了QAQ。然后想出了这个用阶乘+除法的方法。
又因为要对1e9+7取模,所以要用到逆元。再补一波逆元QAQ:
wikipedia-modular_multiplicative_inverse
当模数m与数a互质时,逆元为 am2
快速求逆元的方法:

ni[i]=(mod-mod/i)*ni[mod%i]%mod;

代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define mod 1000000007
#define ll long long
using namespace std;

ll n;
ll maxx=0;

ll a[50000];
ll ss[50000];
ll ni[50000];
void init()
{
    ll i;
    ni[1]=1;
    a[1]=1;
    for(i=2;i<50000;i++)
    {
        a[i]=i*a[i-1]%mod;
        ss[i]=(3+i)*i/2;
        ni[i]=(mod-mod/i)*ni[mod%i]%mod;
    }
}

ll findd(ll l,ll r)
{
    if(l==r-1) return l;
    if(ss[l]==n) return l;
    if(ss[r]==n) return l;
    ll mid=(l+r)/2;
    if(ss[mid]==n) return mid;
    if(ss[mid]<n) return findd(mid,r);
    if(ss[mid]>n) return findd(l,mid);
}

int main()
{
    init();
    ll t;
    scanf("%lld",&t);
    while(t--)
    {
        scanf("%lld",&n);
        if(n<=4)
            printf("%lld\n",n);
        else
        {
            ll k=findd(2,49999);
            //printf("k=%lld\n",k);
            ll x=n-ss[k];///往右移x个数
            //printf("%lld\n",x);
            ll res=1;
            ll i;
            if(x>k)
            {
                // for(i=3;i<2+k;i++)
                //     res=res*i%mod;
                // res=res*(3+k)%mod;
                res=((a[1+k]*ni[2])%mod*(3+k))%mod;
            }
            else
            {
                // for(i=2+k;i>=3+k-x;i--)
                //     res=res*i%mod;
                // for(i=2;i<=1+k-x;i++)
                //     res=res*i%mod;
                res=(a[2+k]*ni[2+k-x])%mod;
            }
            printf("%lld\n",res);
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值