hdu5646(DZY Loves Partition) 划分

来源:互联网 发布:rxjava 源码 编辑:程序博客网 时间:2024/05/01 00:19

DZY Loves Partition
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 1394 Accepted Submission(s): 528

Problem Description
DZY loves partitioning numbers. He wants to know whether it is possible to partition n into the sum of exactly k distinct positive integers.

After some thinking he finds this problem is Too Simple. So he decides to maximize the product of these k numbers. Can you help him?

The answer may be large. Please output it modulo 109+7.

Input
First line contains t denoting the number of testcases.

t testcases follow. Each testcase contains two positive integers n,k in a line.

(1≤t≤50,2≤n,k≤109)

Output
For each testcase, if such partition does not exist, please output −1. Otherwise output the maximum product mudulo 109+7.

Sample Input

4
3 4
3 2
9 3
666666 2

Sample Output

-1
2
24
110888111

Hint

In 1st testcase, there is no valid partition.
In 2nd testcase, the partition is 3=1+2. Answer is 1×2=2.
In 3rd testcase, the partition is 9=2+3+4. Answer is 2×3×4=24. Note that 9=3+3+3 is not a valid partition, because it has repetition.
In 4th testcase, the partition is 666666=333332+333334. Answer is 333332×333334=111110888888. Remember to output it mudulo 109+7, which is 110888111.

记sum(a,k)=a+(a+1)+⋯+(a+k−1)sum(a,k) = a + (a+1) + \cdots + (a+k-1)sum(a,k)=a+(a+1)+⋯+(a+k−1)。

首先,有解的充要条件是sum(1,k)≤nsum(1,k) \le nsum(1,k)≤n(如果没取到等号的话把最后一个kkk扩大就能得到合法解)。

然后观察最优解的性质,它一定是一段连续数字,或者两段连续数字中间只间隔1个数。这是因为1≤a<=b−21\le a<=b-21≤a<=b−2时有ab<(a+1)(b−1)ab<(a+1)(b-1)ab<(a+1)(b−1),如果没有满足上述条件的话,我们总可以把最左边那段的最右一个数字作为aaa,最右边那段的最左一个数字作为bbb,调整使得乘积更大。

可以发现这个条件能够唯一确定nnn的划分,只要用除法算出唯一的aaa使得sum(a,k)≤n

#include<cstdio>#include<cmath>typedef long long ll;const ll LLMAX=(~((unsigned long long) 0))>>1;const ll mod=7LL+1e9;ll n,m;ll f(ll x){    return (m*(m-1+(x<<1)))>>1;}int main(){    int T;    scanf("%d",&T);    while(T--){        scanf("%lld%lld",&n,&m);        if(f(1)>n){            puts("-1");continue;        }        ll s=n/m-(m>>1);        ll sum=f(s);        while(f(s)<=n){            ++s;        }        --s;        sum=f(s);        ll ans=1;        if(sum==n){            for(ll i=s;i<s+m;++i){                ans=(ans*i)%mod;            }        }else{//不能是连续的数了,必须是两端连续的整数            ll movep=m-(n-sum);            for(ll j=s;j<s+movep;++j){                ans=(ans*j)%mod;            }            ll moveq=n-sum;            for(ll j=s+movep+1;j<moveq+s+movep+1;++j){                ans=(ans*j)%mod;            }        }        printf("%lld\n",ans);    }    return 0;}
1 0
原创粉丝点击