Educational Codeforces Round 61 (Rated for Div. 2)E题

在两天的挣扎过后,总算是过了。果然是教育专场。。受教了
首先我们知道这是一个背包问题,不过这个背包太大了,根本没办法像小背包一样去转移。
我们可以思考一个新的算法。
假设第i种,使用了ci=L/ipi+k,其中L是840,即1~8的公倍数。
为什么要这样做呢,我们的目的是,把大背包转移成小的背包。840是任意1~8都能够凑整的数字,我们可以模拟出,对于每一个i,我们最多可以构造出多少个840再加上剩余量k。
将剩余量k,来背包,最后答案就等于n
840加上背包最大结果。其中要小于w才行。
过程感觉蛮复杂的而且很难设计。。
背包量直接设计成8*840,为了方便。
用dp来表示块数,及多少个840。i表示第i位,j表示小背包的量。
状态转移方程:
dp[i][j+k *(i)]=max(dp[i][j],dp[i-1][j]+(cnti-1-k)/(840/(i+1))

#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
typedef pair<int, int> pir;
ll w;
ll a[10];
const int  l = 9;
const int  h = 840;
ll dp[l][l*h];
int main()
{
	cin >> w;
	up(i, 0, 8)
	{
		cin >> a[i];
	}
	memset(dp, -1, sizeof(dp));
	dp[0][0] = 0;
	up(i, 0, 8)
	{
		//cout << 1 << endl;
		upd(j, 0, 8 * h)
		{
			ll b = min(a[i],(ll) h / (i + 1));//背包小量
			if (dp[i][j] == -1)continue;//上个状态没有转移
			upd(k, 0, b)//开始背包
			{
				ll &temp = dp[i + 1][j + k * (i + 1)];
				temp = max(temp, dp[i][j] + (a[i] - k) / (h / (i + 1)));//状态转移,转移840的块数
			}
		}
	}
	ll ans = 0;
	upd(j, 0, 8 * h)
	{
		if (j > w || dp[8][j] == -1)continue;//要加上<840因为可能本来就是小背包
		ans = max(ans, j + h*min(dp[8][j],(w-j)/h));//最终状态的转移
	}
	cout << ans << endl;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44019404/article/details/89196081