DZY Loves Partition
Accepts: 154
Submissions: 843
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。
思路:
首先试了一下: 9拆成3个可以拆分成2+3+4 or 1+3+5,但是很明显前一个的积要大,而且多试了几个都是如此。所以考虑拆成一段连续的数,它们积较大。但是n拆成k个连续数的和后可能有剩余,于是可以考虑吧它们添加到这k个数上面。很明显从前面添加会有重复,所以如果剩余了m,则在倒数m个数上面均加上1.
#include <iostream> #include <cstdio> #include <cstring> #include <vector> #include <map> #include <algorithm> using namespace std; typedef long long ll; #define LL(x) (x<<1) #define RR(x) (x<<1|1) const ll MOD = 1e9 + 7; const int maxn = 305; int main() { int T; ll n,k; ll t; scanf("%d",&T); while(T--) { scanf("%I64d%I64d",&n,&k); if(k%2) t = (ll)(k+1)/2*k; else t = (ll)k/2*(k+1); if(t > n) { printf("-1 "); continue ; } else { ll po = n-t; ll bei = po/k; ll els = po%k; //cout << bei <<" "<<els<<endl; ll ans = 1; for(ll i = k; i >= 1; i--) { ll cur = i+bei; if(els) { cur++; els --; } ans = (ll)ans*cur%MOD; } printf("%I64d ",ans); } } return 0; }