n根木棍长度为Li依次连接在一起, 最多砍断m个连接处, 问长度最大的一段的最小长度, 并求出使长度最大的一段最短的方案数模10007. (n≤5*10^4, 0≤m≤min(n-1,1000), 1≤Li≤1000) 第一问就是 NOIP 2015 D2 T1, 二分, 贪心地验证.
第二问DP. 由于最大长度已知, 所以状态只有两维:
以为长度的最大值是否取得到
事实上, 并不存在这个问题, 因为
满足
遭遇0s TLE的惨案......数组得滚动一下.
const int MOD = 10007, N = 5e4, M = 1e3;
// f[0]: max < r, f[1]: max = r
// g[0][i]: f[0][0..i], g[1][i] : f[1][0..i]
int n, m, l, r, a[N+1], s[N+1], f[2][2][N+1], g[2][2][N+1];
bool check(int c)
{
for (int x = 0, y = 0, cnt = -1; x < n; x = y) { // (x, y]
while (y <= n && s[y] - s[x] <= c) ++y;
--y;
if (++cnt > m) return false;
}
return true;
}
void bs()
{
while (r-l > 1) { // (l, r]
int m = (l+r)/2;
if (check(m)) r = m;
else l = m;
}
}
int solve()
{
rep (y, 1, n+1) {
g[0][0][y] = g[0][0][y-1] + (f[0][0][y] = s[y] < r) % MOD;
g[1][0][y] = g[1][0][y-1] + (f[1][0][y] = s[y] == r) % MOD;
}
int ans = f[1][0][n];
rep (j, 1, m+1) {
int t = j & 1;
for (int y = 1, x = 0; y <= n; ++y) {
while (s[y] - s[x] > r) ++x;
f[1][t][y] = ((s[y]-s[x] == r ? f[0][t^1][x] : 0) + g[1][t^1][y-1] - (x ? g[1][t^1][x-1] : 0)) % MOD;
f[0][t][y] = (g[0][t^1][y-1] - g[0][t^1][x] + (s[y]-s[x] < r ? f[0][t^1][x] : 0)) % MOD;
g[1][t][y] = (g[1][t][y-1] + f[1][t][y]) % MOD;
g[0][t][y] = (g[0][t][y-1] + f[0][t][y]) % MOD;
}
(ans += f[1][t][n]) %= MOD;
}
return (ans + MOD) % MOD;
}
int main()
{
scanf("%d%d", &n, &m);
rep (i, 1, n+1) {
scanf("%d", a+i);
s[i] = s[i-1] + a[i];
l = max(l, a[i]);
}
--l;
r = s[n];
bs();
printf("%d %d\n", r, solve());
return 0;
}