版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_37753409/article/details/82927638
【HDU-5976 Detachment】
题意: 给定一个数字分成若干段, 要求每一段的长度不相等, 要求这些段的乘积最大。
分析: 这是一个标准的Maximum Product Over Partitions Into Distinct Parts 问题,打表找规律, 参见论文
#include <algorithm>
#include <cstdio>
#include <iostream>
using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;
const int MAXN = 1e5 + 10;
ll tr[MAXN];
ll fa[MAXN];
void get_tr () {
for (int i = 1; i < MAXN; i++)
tr[i] = (long long)(i + 1)*(long long)i/2;
}
void get_fa() {
fa[0] = 1;
for (int i = 1; i < MAXN; i++) {
fa[i] = ((long long)i*fa[i-1])%mod%mod;
}
}
long long extend_gcd (ll a, ll b, ll &x, ll &y) {
if (a == 0 && b == 0) return -1;
if (b == 0) {
x = 1; y = 0; return a;
}
long long d = extend_gcd(b, a%b, y, x);
y -= a/b*x;
return d;
}
ll inv (ll a, ll m) {
long long x, y;
long long d = extend_gcd (a, m, x, y);
if (d == 1) return (x%m + m)%m;
else return -1;
}
int main () {
int T;
long long n;
get_fa();
get_tr();
scanf ("%d", &T);
/*
for (int i = 1; i < 100; i++) {
cout << tr[i] << endl;
}
*/
while (T--) {
scanf ("%lld", &n);
if (n == 1){
printf("1\n");
continue;
}
ll l = 0;
int m = lower_bound (tr + 1, tr + MAXN - 1, n) - tr;
if (tr[m] == n) l = 0;
else {
m = m - 1;
l = n - tr[m];
}
/*
for (int i = 1; i < MAXN; i++) {
if (n < tr[i]) {
m = i - 1;
break;
}
}
*/
ll t = fa[m];
ll p = (ll)m;
if (l >= 0 && l <= p - 2) {
printf ("%lld", ((t*(p + 1))%mod*inv(p - l, mod))%mod%mod);
} else if (l == m - 1) {
printf ("%lld", (t*(p + 2))%mod*inv(2, mod)%mod)%mod;
} else if (l == m) {
printf ("%lld", t*(p+1)%mod%mod);
}
printf("\n");
}
return 0;
}