题目链接
http://main.edu.pl/en/archive/oi/19/sza
题目大意
有n件物品,每件物品有三个属性a[i], b[i], c[i] (
a[i]<b[i]
)。
再给出q个询问,每个询问由非负整数m, k, s组成,问是否能够选出某些物品使得:
1. 对于每个选的物品i,满足a[i]<=m且b[i]>m+s。
2. 所有选出物品的c[i]的和正好是k。
思路
如果对于每次询问都从头开始做背包的话,那么肯定TLE。
考虑离线处理,一次背包回答所有的询问。对每个询问按照
m
升序排序,对每个物品按照
代码
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#define MAXN 1100
#define MAXK 110000
#define MAXQ 1100000
#define INF 0x3f3f3f3f
using namespace std;
int n,q;
struct Thing
{
int a,b,c;
}things[MAXN];
struct Query
{
int m,k,s,id;
}query[MAXQ];
bool ans[MAXQ];
bool cmp_thing(Thing a,Thing b)
{
return a.a<b.a;
}
bool cmp_query(Query a,Query b)
{
return a.m<b.m;
}
int f[MAXK];
int main()
{
int maxx=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d%d%d",&things[i].c,&things[i].a,&things[i].b);
scanf("%d",&q);
for(int i=1;i<=q;i++)
query[i].id=i,scanf("%d%d%d",&query[i].m,&query[i].k,&query[i].s),maxx=max(maxx,query[i].k);
sort(things+1,things+n+1,cmp_thing);
sort(query+1,query+q+1,cmp_query);
f[0]=INF;
for(int i=1,j=1,sum=0;i<=q;i++) //回答第i个询问,当前决策是否放入第j个物品
{
for(;j<=n&&things[j].a<=query[i].m;sum+=things[j].c,j++)
for(int k=min(maxx,sum);k>=0;k--)
if(f[k])
f[k+things[j].c]=max(f[k+things[j].c],min(things[j].b,f[k]));
ans[query[i].id]=f[query[i].k]>(query[i].m+query[i].s);
}
for(int i=1;i<=q;i++)
printf("%s\n",ans[i]?"TAK":"NIE");
return 0;
}