洛谷P1877 [HAOI2012] 音量调节 题解

本题做法

  • 0-1 背包 DP。

思路

定义 \(dp[i][j]\) 表示在前 $i 首歌曲是否可以达到音量 \(j\)(是的话为 \(\text{true}\),否则为 \(\text{false}\))。因为音量 \(j\) 可以由音量 \((j+c[i])\) 降低 \(c[i]\) 或者由音量 \((j-c[i])\) 升高 \(c[i]\) 转移而来,并且这 2 个音量只需要满足其中一个即可,所以需要用位运算“或”转移。

所以我们得到状态转移方程:

\[dp[i][j]=dp[i-1][j-c[i]]\text{ or }dp[i-1][j+c[i]]~(c[i]\le j\le maxLevel-c[i]) \]

根据此方程进行写 0-1 背包 DP 代码就行了。

代码

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;

const int N=55;
const int V=1005;

ll n,c[N],beg,maxx;
bool dp[N][V];

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cin>>n>>beg>>maxx;
    for(int i=1;i<=n;i++) cin>>c[i];
    dp[0][beg]=1;
    for(int i=1;i<=n;i++){
        for(int j=0;j<=maxx;j++){
            if(j-c[i]>=0) dp[i][j]|=dp[i-1][j-c[i]];
            if(j+c[i]<=maxx) dp[i][j]|=dp[i-1][j+c[i]];
        }
    }
    for(int i=maxx;i>=0;i--){
        if(dp[n][i]==1){
            cout<<i<<endl;
            return 0;
        }
    }
    cout<<-1<<endl;
    return 0;
}
posted @ 2025-08-06 14:31  2789617221guo  阅读(49)  评论(0)    收藏  举报