[HAOI2012] 音量调节
题目描述
一个吉他手准备参加一场演出。他不喜欢在演出时始终使用同一个音量,所以他决定每一首歌之前他都需要改变一次音量。在演出开始之前,他已经做好一个列表,里面写着每首歌开始之前他想要改变的音量是多少。每一次改变音量,他可以选择调高也可以调低。
音量用一个整数描述。输入文件中整数 $beginLevel$,代表吉他刚开始的音量,整数 $maxLevel$,代表吉他的最大音量。音量不能小于 $0$ 也不能大于 $maxLevel$。输入中还给定了 $n$ 个整数 $c_1,c_2,c_3,\cdots,c_n$,表示在第 $i$ 首歌开始之前吉他手想要改变的音量是多少。
吉他手想以最大的音量演奏最后一首歌,你的任务是找到这个最大音量是多少。
输入格式
第一行依次为三个整数 $n$,$beginLevel$ 和 $maxLevel$。
第二行依次为 $n$ 个整数 $c_1,c_2,c_3,\cdots,c_n$。
输出格式
输出演奏最后一首歌的最大音量。如果吉他手无法避免音量低于 $0$ 或者高于 $maxLevel$,输出 -1。
样例 #1
样例输入 #1
样例输出 #1
提示
$1\le n\le 50$,$1\le c_i\le maxLevel$,$1\le maxLevel\le 1000$,$0\le beginLevel\le maxLevel$。
题解
题目解析
一道另类的背包题目, 到达型的背包. 类似于二分答案的到达型解法. 一句话总结就是把所有的可能到达的结果都跑一遍.
定义一个数组dp[i][j]=第i个歌曲是否可以凑成j的音乐(1为可以,0则不可以) 
接着是这样考虑的:
很好理解, 前面可以组成 $j-a[i]$ 的时候我们可以加上 $a[i]$ 凑成 $j$ 然后把关于 $j$ 的dp数组设置成 $1$ . 如果是 $j + a[i]$ 则是在之前的结果上减去 $a[i] $.
这样我们遍历从 $0$ 到 $maxLevel$ 就完事了, 最后输出相应的值就可了.
AC代码
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 
 | #include <bits/stdc++.h>using namespace std;
 
 #define endl "\n"
 #define CIN_ ios::sync_with_stdio(0)
 #define CIN cin.tie(0)
 #define MAXN(size) const long long MAXN = size + 100
 #define MOD(size) const long long MOD = size
 #define mem(name,value) memset(name,value,sizeof(name))
 #define fa(i,a,n) for(int i=a;i<=n;++i)
 #define fb(i,a,n) for(int i=a;i>=n;--i)
 #define T_ int T;cin >> T;while(T--)
 typedef pair<int,int> PII;
 typedef long long ll;
 typedef unsigned long long ull;
 
 MAXN(1000);
 int a[MAXN],dp[100][MAXN];
 
 signed main(){
 CIN_;CIN;
 int n,b,m;
 cin >> n >> b >> m;
 dp[0][b] = 1;
 fa(i,1,n) cin >> a[i];
 fa(i,1,n){
 fb(j,m,0){
 if(j - a[i] >= 0 && dp[i-1][j - a[i]]) dp[i][j] = 1;
 if(a[i] + j <= m && dp[i-1][j + a[i]]) dp[i][j] = 1;
 }
 }
 fb(i,m,1){
 if(dp[n][i]){
 cout << i << endl;
 return 0;
 }
 }
 cout << -1 << endl;
 return 0;
 }
 
 | 
我在考虑的时候, 想把它用 $n \% 2$ 压缩, 这样可以只开 $2$ 个维. 但是事实上我们在转移的时候, 之前的状态被正确转移. 但是上上次的状态同时也存在在里面, 于是我想到另外一个解决方法.
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 
 | fa(i,1,n){int p = i % 2;
 fb(j,m,0){
 dp[p%2][j] = 0;
 if(j - a[i] >= 0 && dp[(p+1)%2][j - a[i]]) dp[p][j] = 1;
 if(a[i] + j <= m && dp[(p+1)%2][j + a[i]]) dp[p][j] = 1;
 }
 }
 fb(i,m,1){
 if(dp[n%2][i]){
 cout << i << endl;
 return 0;
 }
 }
 
 |