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;
}
posted @ 2022-07-14 12:06  notyour_young  阅读(241)  评论(10编辑  收藏  举报