BZOJ2794 [Poi2012]Cloakroom [离线][DP]
Description
有n件物品,每件物品有三个属性a[i], b[i], c[i] (a[i]
Input
第一行一个正整数n (n<=1,000),接下来n行每行三个正整数,分别表示c[i], a[i], b[i] (c[i]<=1,000, 1<=a[i]
Output
输出q行,每行为TAK (yes)或NIE (no),第i行对应第i此询问的答案。
题解
感觉波兰的题好多都是思维题…
选出的物品有两个要求,第二个要求只能用DP了,所以必须在第一个要求上优化
一开始考虑了一下离线,但是毫无思路
离线:
首先将每个物品按照 的值从小到大排序,其次将询问按照 的值从小到大排序
这样就不用每次重新寻找 的临界值,从 变为 ;而且此时只用寻找这些物品( 值之和恰好为 )中 的最小值,只要这个最小值大于 ,就TAK,否则NIE
然后背包DP:设定状态 表示当物品的 值和为 时,这些物品中 的最小值
方程:见代码
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
struct node{int a,b,c;}Att[1100];
struct Node{int m,k,s,id;}Que[1000100];
bool operator<(const node &w,const node &e){
return w.a<e.a;
}
bool operator<(const Node &w,const Node &e){
return w.m<e.m;
}
int f[100100];bool Ans[1000100];
int main(){
int n,Max=0;scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d%d%d",&Att[i].c,&Att[i].a,&Att[i].b);
sort(Att+1,Att+n+1);
int q;scanf("%d",&q);
for(int i=1;i<=q;i++){
scanf("%d%d%d",&Que[i].m,&Que[i].k,&Que[i].s);
Max=max(Max,Que[i].k);Que[i].id=i;
}
sort(Que+1,Que+q+1);f[0]=1e9;
for(int cnt=1,i=1;cnt<=q;cnt++){
while(Att[i].a<=Que[cnt].m && i<=n){
for(int t=Max;t>=Att[i].c;t--)
f[t]=max(f[t],min(f[t-Att[i].c],Att[i].b));
i++;
}
if(f[Que[cnt].k]>Que[cnt].m+Que[cnt].s)
Ans[Que[cnt].id]=true;
}
for(int i=1;i<=q;i++)
if(Ans[i])puts("TAK");else puts("NIE");
return 0;
}