[刷题笔记] Luogu P2340 [USACO03FALL] Cow Exhibition G
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;
}
本文作者:SXqwq,转载请注明原文链接:https://www.cnblogs.com/SXqwq/p/17600671.html