分组背包

题目

  1. https://leetcode.cn/problems/number-of-ways-to-earn-points/description/?orderBy=most_votes

  2. https://codeforces.com/problemset/problem/148/E

题意(仅第二题)

  • 开始给两个数n,op
  • n个双端队列,每个长度为m(\(1 \leq n \leq 100,1 \leq m \leq 100\)
  • 问从中取出op个元素,取出元素总和最大是多少

第二题思路(都是分组背包)

  • 第一题题解
  • 把每一个deque看成是一个分组,分组中的物品就是deque前缀和后缀的所有可能组合
  • 但是这样进行分组背包的时间复杂度是O(nop\(n^2\)),所以我们需要再提炼一下,长度相同的组合,必然选择值最大的哪一个
  • 这样对所有分组先做一次前缀和,维护长度相同的组合,值最大的情况\(O(n^3)\)
  • 最后用分组背包模板,\(O(n^2*op)\)
  • 1e8可过,因为背包过程中操作不多,hhh
  • 不要忘记开LL

代码

const int N = 110,M = 10010;
int f[M];
int ed[N];
int a[N][N];
int val[N][N];

void solve()
{
	int n,m;cin >> n >> m;

	for(int i = 1;i <= n;i ++)
	{
		cin >> ed[i];
		for(int j = 1;j <= ed[i];j ++)
		{
			cin >> a[i][j];
			a[i][j] += a[i][j-1];
		}
		a[i][ed[i]+1] = a[i][ed[i]];
	}

	for(int i = 1;i <= n;i ++)
	{
		for(int l = 0;l <= ed[i];l ++)
			for(int r = l+1;r <= ed[i]+1;r ++)
			{
				int &t = val[i][l + ed[i]+1 - r];
				t = max(t,a[i][l] + a[i][ed[i]+1] - a[i][r-1]);
			}
	}

	for(int i = 1;i <= n;i ++)
	{
		for(int j = m;j >= 1;j --){
			for(int k = 0;k <= ed[i];k ++)
			{
				int va = val[i][k];
				
				if(j - k >= 0)f[j] = max(f[j-k] + va,f[j]);
			}
		}
	}

	cout << f[m] << endl;
}
posted @ 2023-03-07 20:54  俄罗斯刺沙蓬  阅读(13)  评论(0编辑  收藏  举报
返回顶端