题解 P2577 【[ZJOI2005]午餐】
安利博客->wjyyy
题解:
首先这个题需要用贪心来将每个人排序,否则无法进行唯一的DP。但是贪心会有两个思路,分别是按吃饭时间降序排序,和按打饭+吃饭时间之和降序排序,因为我们要避免吃饭时间长的人后打饭。因此下面的证明只考虑这两种情况。
设第
这样可以先把每个人排序,然后就可以做一个类似背包的DP了。设f[i][j][k]表示排完了
考虑到时间复杂度主要由状态个数贡献,因此考虑压维。我们看到,当贪心地排序后,序列是一定的。因此
这个题的主要思维在贪心。同时较难的地方还有压掉一维,不过见得多了也许就是一种套路了吧。
Code:
#include<cstdio>
#include<cstring>
#include<algorithm>
using std::min;
using std::max;
struct pp
{
int x,y;
friend bool operator <(pp a,pp b)
{
return a.y>b.y;
}
}a[222];
int f[205][40005];
int main()
{
memset(f,0x3f,sizeof(f));
f[0][0]=0;
int n;
scanf("%d",&n);
for(int i=1;i<=n;++i)
scanf("%d%d",&a[i].x,&a[i].y);
std::sort(a+1,a+1+n);
int tt=0;
for(int i=1;i<=n;++i)
{
for(int j=0;j<=200*i;++j)
if(j<a[i].x)
f[i][j]=max(f[i-1][j],tt-j+a[i].x+a[i].y);
else
f[i][j]=min(max(f[i-1][j-a[i].x],j+a[i].y),max(f[i-1][j],tt-j+a[i].x+a[i].y));
tt+=a[i].x;
}
long long ans=0x7ffffffffff;
for(int i=0;i<=200*n;++i)
ans=ans<f[n][i]?ans:f[n][i];
printf("%lld\n",ans);
return 0;
}