#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 4E5 + 10;
const int INF = 0x3f3f3f3f;
int init[maxn], sum[maxn], dp[maxn][2], n, m, d, T;
bool check(int x)
{
memset(dp, INF, sizeof(dp));
dp[0][0] = 0;
for (int i = 2; i <= n; i += 2)
for (int len = 1; len <= d && len * 2 <= i && x >= sum[i] - sum[i - len]; len++)
if (x >= sum[i - len] - sum[i - 2 * len])
{
dp[i][0] = min(dp[i][0], dp[i - 2 * len][1] + 1);
dp[i][1] = min(dp[i][1], dp[i - 2 * len][0] + 1);
}
return dp[n][!(m & 1)] <= m - 1;
}
int main(int argc, char const *argv[])
{
scanf("%d", &T);
while (T--)
{
scanf("%d%d%d", &n, &m, &d);
sum[0] = 0;
for (int i = 1; i <= n; i++)
scanf("%d", init + i), sum[i] = sum[i - 1] + init[i];
if ((n & 1) || (n < 2 * (m - 1)) || n > 2 * (m - 1)*d) printf("BAD\n");
else
{
int L = 1, R = sum[n], mid;
while (L < R)
{
mid = (L + R) / 2;
if (check(mid)) R = mid;
else L = mid + 1;
}
printf("%d\n", L);
}
}
return 0;
}
N个数,分成m-1段,每段长度不超过2*d,求所有半段中,最大重量的最小值。
最大重量最小值,典型二分题,根据最小值x进行dp,最大不超过x进行分段,dp[i][2]表示前i个符合要求的最小段数,小于m-1则可以。
奇偶分开便于dp