C - DZY Loves Partition

探讨如何将一个整数拆分成若干不同整数之和,并使这些整数的乘积最大,同时给出两种实现算法及其代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

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

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

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

(1t50,2n,k1091≤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+7109+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、付费专栏及课程。

余额充值