[刷题笔记] Luogu P2340 [USACO03FALL] Cow Exhibition G

Problem

Solution

乍看可能没有思路。我们注意到本题是牵扯到一头奶牛选or不选的问题,非常自然地想到01背包

接下来我们就尝试将本题背景转换成01背包问题。

我们可以将智商转换成容量,情商转换成价值。(当然反过来也可)

然后就可以套用01背包板子了:

\[f_{i,j}=min(f_{i-1,j},f_{i-1,j-w_i}+v_i) \]

但是如果交上去会满屏MLE...

而且本题与01背包不同的是,本题奶牛的IQ值会出现负数,显然很有可能中间出现负数最后变成正数了。如果直接使用IQ作下表会溢出。

怎么办呢?

我们可以将IQ值加上一个MAXN,处理的时候都加上MAXN,正好抵消,不会对答案造成影响,也解决了溢出的问题。

那么对于MLE如何解决呢?

显然和01背包同理,我们每次操作只依赖于前一次操作,和01背包优化掉一维就好啦!状态转移方程和一维01背包是完全一样的!

还要注意的问题是对于每个IQ值,如果本次IQ值是负数需要正着搜,因为负数是从左到右转移的。

至此,本题得解,代码如下:

Code

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring> 
#define N 1000010
#define MAX 100000
#define INF 0x3f3f3f3f
using namespace std;
int n;
int eq[N],iq[N];
int f[N];
int maxn = -1;
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d%d",&iq[i],&eq[i]);
	memset(f,-INF,sizeof(f)); //初始化为负的极大值,因为IQ显然可以是负数
	f[0+MAX] = 0; //数组偏移
	for(int i=1;i<=n;i++)
	{
		if(iq[i] > 0) //是正数则倒着搜
		{
			for(int j=MAX;j>=-MAX;j--) 
			{
				if(j-iq[i] >= -MAX && j-iq[i] <= MAX)
				{
					f[j+MAX] = max(f[j+MAX],f[j+MAX-iq[i]]+eq[i]);
				}
			}
		}
		else//是负数正着搜
		{
			for(int j=-MAX;j<=MAX;j++) 
			{
				if(j-iq[i] >= -MAX && j-iq[i] <= MAX)
				{
					f[j+MAX] = max(f[j+MAX],f[j+MAX-iq[i]]+eq[i]);
				}
			}
		}
	}
	for(int i =0;i<=MAX;i++) 
	{
		if(f[i+MAX] > 0) //如果满足条件,EQ值用f数组控制,IQ值用i控制,枚举的是IQ值
			maxn = max(maxn,f[i+MAX]+i); //取iq和eq的和
	}
	cout<<maxn<<endl;
	return 0;
}
posted @ 2023-08-02 14:53  SXqwq  阅读(27)  评论(0编辑  收藏  举报