题意

终于Alice走出了大魔王的陷阱,可是现在傻傻的她忘了带武器了,这可如何是好???这个时候,一个神秘老人走到她面前答应无偿给她武器,但老人有个条件,需要将所选武器分别放在天平的两端,若天平平衡则可以将天平上的所有武器拿走,还好这个天平锈迹斑斑,只要两端重量相差小于等于m就会保持平衡,Alice傻傻的认为越重的武器越好,求Alice最多能拿走的武器总重量。(不限操作次数)
其中,

分析

这题还是比较简单滴。
首先,容易发现,称多次和称一次没有区别,也就是称一次就可以得到最终的答案。假如你称两次,第一次为 ,第二次为 ,其中 ,那么我们完全可以变成称一次 ,使得最终答案不变。所以称多次最后都可以变成称一次。
然后由于最终的限制条件是差值,我们令 表示前 个物品,大的减小的差值为 的最大武器重量。
转移分三种:

  1. 武器太辣鸡了,不取
  2. 把武器加入小的那边
  3. 把武器加入大的那边

然后由于差值可能是负数,我们要给他加上一个大整数。
最终复杂度是 的。

代码如下

#include <bits/stdc++.h>

using namespace std;

int read(){
    int x, f = 1;
    char ch;
    while(ch = getchar(), ch < '0' || ch > '9') if(ch == '-') f = -1;
    x = ch - '0';
    while(ch = getchar(), ch >= '0' && ch <= '9') x = x * 10 + ch - 48;
    return x * f;
}

const int N = 105, maxn = 20000;
int f[N][N * N * 5];

int main(){
    int i, j, k, n, m, ans = 0;
    n = read(); m = read();
    memset(f, 0xc0, sizeof(f));
    f[0][maxn] = 0;
    for(i = 1; i <= n; i++){
        k = read();
        for(j = -10000; j <= 10000; j++){
            f[i][j + maxn] = max(f[i - 1][j + k + maxn], f[i - 1][j - k + maxn]) + k;
            f[i][j + maxn] = max(f[i][j + maxn], f[i - 1][j + maxn]);
        }
    }
    for(i = -m + maxn; i <= m + maxn; i++) ans = max(ans, f[n][i]);
    printf("%d", ans);
    return 0;
}