Codeforces Round #806 (Div. 4)G. Good Key, Bad Key(背包dp)
G. Good Key, Bad Key
题意 :有n个宝箱\((0 \le n \le 1e5)\),第i个宝箱有\(a_i\)个金币,每次可以选择使用两种钥匙开箱
1.好🔑 花费k个金币
2.坏🔑 不花金币但会使以后的金币都减半
要求我们必须按顺序开箱,问最后可得到最多的金币个数为多少
考虑dp
注意一个32位整数最多除31次就会变成0,所以第二维开32就好,特别的用32来表示用的坏🔑个数 $\geq $ 31 的状态
ac代码
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <queue>
#include <map>
#include <vector>
#include <stack>
#include <set>
#include <sstream>
#include <fstream>
#include <cmath>
#include <iomanip>
#include <bitset>
#include <unordered_map>
#include <unordered_set>
#define x first
#define y second
#define ios ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define endl '\n'
#define pb push_back
#define all(x) x.begin(),x.end()
#define all1(x) x.begin()+1,x.end()
#define pi 3.14159265358979323846
//#define int long long
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
const int N = 10010,M = 400010,INF = 0x3f3f3f3f,mod = 10007;
const double INFF = 0x7f7f7f7f7f7f7f7f;
int n,m,k,t;
int main()
{
ios;
cin >> t;
while(t --)
{
cin >> n >> k;
vector<LL> a(n + 1);
for(int i = 1;i <= n;i ++) cin >> a[i];
vector<vector<LL>> f(n + 1,vector<LL> (33,-1e18));
f[0][0] = 0;
for(int i = 1;i <= n;i ++)
for(int j = 0;j <= min(32,i);j ++)
{
f[i][j] = f[i - 1][j] + (a[i] >> j) - k;
if(j) f[i][j] = max(f[i][j],f[i - 1][j - 1] + (a[i] >> j));
if(j >= 31) f[i][j] = max(f[i - 1][j],f[i][j]);
}
LL res = 0;
for(int i = 0;i <= 32;i ++) res = max(res,f[n][i]);
cout << res << endl;
}
return 0;
}