题目链接在这儿:链接说明

题意:中文题

思路:
为什么不能用深搜+减脂?
尝试了一发,果然TLE了,因为理论上是2^50次方的运算。
有一个小小减脂是:后缀和,如果当前的值加后面所有的值不超过当前记录的最大值,就返回。
超时代码也贴一下:

#include <bits/stdc++.h>
using namespace std;

const int maxn = 55;
int n, k, m;
int a[maxn];
int sumafter[maxn];
int flag;

void dfs(int step, int sum){
    if (sum + sumafter[step] <= flag) return;
    if (flag == m) return;
    if (sum + sumafter[step] <= m){
            flag = max(flag, sum + sumafter[step]);
            return;
        }
    if (step == n + 1){
        flag = max(flag, sum);
        return;
    }    
    if (sum - a[step] >= 0) dfs(step + 1, sum - a[step]);
    if (sum + a[step] <= m) dfs(step + 1, sum + a[step]);
    return;
}

int main(){
    //freopen("input.txt", "r", stdin);
    flag = -1;
    scanf("%d%d%d", &n, &k, &m);
    memset(a, 0, sizeof(a));
    memset(sumafter, 0, sizeof(sumafter));
    for(int i = 1; i <= n; i++)
        scanf("%d", &a[i]);
    for(int i = n; i >= 1; i--)
        sumafter[i] = sumafter[i + 1] + a[i];
    dfs(1, k);
    printf("%d\n", flag);
    return 0;
}

超时了说明时间不够,那就拿空间来凑。把所有数据记录下来。
data[i][j]表示当弹奏到第 i 个时,是否可以达到 j 的音量。
根据初始数据,i这一维变量最大为 50,j这一维变量最大为 1000,数组合理。
复杂度呢?
data[i][j]可以根据data[i-1]的数据来算,而且不需要开 int 值,开 bool 值即可。
初始化是 data[0][初始音量值] = 1,其他都为 0。
说是dp,理解就是第 i 阶段的所有数据可以由第 i-1 阶段的所有数据推出来。我个人理解这个题是打表,把合法的数据全部打出来,存在就是1,不存在就是0。
代码如下。

#include<bits/stdc++.h>
using namespace std;

bool data[55][1050];
int n, k, m;
int a[1050];
int flag;

int main(){
    //freopen("input.txt", "r", stdin);
    scanf("%d%d%d", &n, &k, &m);
    for(int i = 1; i <= n; i++)
        scanf("%d", &a[i]);
    memset(data, 0, sizeof(data));
    data[0][k] = 1;
    for(int i = 1; i <= n; i++)
        for(int j = 0; j <= m; j++)
            if (data[i-1][j] == 1){
                if (j + a[i] <= m) data[i][j + a[i]] = 1;
                if (j - a[i] >= 0) data[i][j - a[i]] = 1;
            }
    flag = -1;
    for(int j = m; j >= 0; j--)
        if (data[n][j]){
            flag = j;
            break;
        }
    printf("%d\n", flag);
    return 0;
}