C - DZY Loves Partition

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

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

The answer may be large. Please output it modulo  109+7 109+7
Input
First line contains  t t denoting the number of testcases. 

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

( 1t50,2n,k109 1≤t≤50,2≤n,k≤109
Output
For each testcase, if such partition does not exist, please output  1 −1. Otherwise output the maximum product mudulo  109+7 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\times 2 = 2$.
In 3rd testcase, the partition is $9=2+3+4$. Answer is $2\times 3 \times 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\times 333334= 111110888888$. Remember to output it mudulo $10^9 + 7$, which is $110888111$.
   
   
题意:
给你个数n,拆k个各不相同的数之和,并且使得k个数的乘积最大,最后输出k个数乘积对1e9+7取模的结果!
思路:
令sum(a,b),为a + (a + 1) + (a + 2)....+b的结果!
先取得的一个数a使得sum(a,a+k-1)刚好小于n,
最后多出来的数字加到这一串数后面,每个数加1就行了!
通过二分来查找最大的a
二分:
先对n取半,如果此时sum(a,a+k-1)比n大,则向左找,否则向右找,并且记录最大值MAX
如果最后发现MAX 没变的话,则不存在一个a满足式子,则直接输出-1
否则就用那个a即可!
代码1
  1. #include<cstdio>  
  2. #include<cmath>  
  3. #include<algorithm>  
  4. using namespace std;  
  5. typedef long long ll;  
  6. const int mod = 1e9+7;  
  7. ll sum(ll a,ll b){  
  8.     ll num = b-a+1;  
  9.     ll ans;  
  10.     ans = num%2 ? (a+b)/2*num : num/2*(a+b);  
  11.     return ans;  
  12. }  
  13. int main(){  
  14.     int T;  
  15.     scanf("%d",&T);  
  16.     while(T--){  
  17.         ll n,k;  
  18.         scanf("%lld%lld",&n,&k);  
  19.         ll MAX = -1;  
  20.         ll a,l=1,r=n;  
  21.         while(l <= r){  
  22.             ll mid =(r+l)/2;  
  23.             ll tmp = sum(mid,mid+k-1);  
  24.             if (tmp > n)r = mid-1;  
  25.             if (tmp <= n){  
  26.                 l = mid + 1;  
  27.                 if (tmp > MAX){  
  28.                     MAX = tmp;  
  29.                     a = mid;  
  30.                 }  
  31.             }  
  32.         }  
  33.         if (MAX == -1){  
  34.             printf("-1\n");  
  35.             continue;  
  36.         }  
  37.         ll tp = n-MAX;  
  38.         ll ans = 1;  
  39.         for (int i = a; i < a+k; ++i){  
  40.             if (i >= a+k-tp)ans=(ans%mod*((i+1)%mod)%mod)%mod;  
  41.             else ans = (ans %mod * i%mod)%mod;  
  42.         }  
  43.         printf("%lld\n",ans);  
  44.     }  
  45.     return 0;  
  46. }  
代码2
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6+5;
const int mod = 1e9+7;
long long n,k;
long long a[maxn];
void solve()
{
    scanf("%lld%lld",&n,&k);
    if(1ll*(1+k)*k/2>n)
    {
        puts("-1");
        return;
    }
    int l = 1,r = n,ans = 1;
    while(l<=r)
    {
        int mid=(l+r)/2;
        if(1ll*(mid+mid+k-1)*k/2<=n)l=mid+1,ans=mid;
        else r=mid-1;
    }
    int p = (n-1ll*(ans+ans+k-1)*k/2);
    for(int i=1;i<=k;i++)a[i]=ans+(i-1);
    for(int i=k;i>k-p;i--)a[i]++;
    long long Ans = 1;
    for(int i=1;i<=k;i++)
        Ans=(Ans*a[i])%mod;
    cout<<Ans<<endl;
}
int main()
{
    int t;scanf("%d",&t);
    while(t--)solve();
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值