DZY Loves Partition
Accepts: 128
Submissions: 272
Time Limit: 4000/2000 MS (Java/Others)
Memory Limit: 262144/262144 K (Java/Others)
问题描述
DZY喜欢拆分数字。他想知道能否把n拆成恰好k个不重复的正整数之和。 思考了一会儿之后他发现这个题太简单,于是他想要最大化这k个正整数的乘积。你能帮帮他吗? 由于答案可能很大,请模109+7输出。
输入描述
第一行t,表示有t组数据。 接下来t组数据。每组数据包含一行两个正整数n,k。 (1≤t≤50,2≤n,k≤109)
输出描述
对于每个数据,如果不存在拆分方案,输出−1;否则输出最大乘积模109+7之后的值。
输入样例
4 3 4 3 2 9 3 666666 2
输出样例
-1 2 24 110888111
Hint
第一组数据没有合法拆分方案。 第二组数据方案为3=1+2,答案为1×2=2 第三组数据方案为9=2+3+4,答案为2×3×4=24。注意9=3+3+3是不合法的拆分方案,因为其中包含了重复数字。 第四组数据方案为666666=333332+333334,答案为333332×333334=111110888888。注意要对109+7取模后输出,即110888111。
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b>a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b<a)a = b; }
const int N = 0, M = 0, Z = 1e9 + 7, ms63 = 0x3f3f3f3f;
int casenum, casei;
LL n, k;
LL solve()
{
LL minv = (1 + k)*k / 2;
if (minv > n)return -1;
LL more = (n - minv) / k;
LL rst = (n - minv) % k;
LL ret = 1;
LL x = k - rst;
for (LL i = 1; i <= x; ++i)
{
ret = ret*(i + more) % Z;
}
for (LL i = x + 1; i <= k; ++i)
{
ret = ret*(i + more + 1) % Z;
}
return ret;
}
int main()
{
scanf("%d", &casenum);
for (casei = 1; casei <= casenum; ++casei)
{
scanf("%lld%lld", &n, &k);
printf("%lld\n", solve());
}
return 0;
}
/*
【题意】
把n(1e9)拆分成k(1e9)个不重复正整数之和。
使得乘积尽可能大。
【类型】
贪心
【分析】
其实最多拆成1e5个数。
如何使得乘积最大?
首先我们拆成最小的k个数,即(1+k)*k/2,
然后如果可以均匀提升肯定均匀提升,
然后多出来的数字我们提升较大的数。
就AC啦>_<~
【时间复杂度&&优化】
O(sqrt(n))
*/