Bzoj2794

Bzoj 2794

【BZOJ2794】[Poi2012]Cloakroom
Description
有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。

Input
第一行一个正整数n (n<=1,000),接下来n行每行三个正整数,分别表示c[i], a[i], b[i] (c[i]<=1,000, 1<=a[i]<b[i]<=10^9)。
下面一行一个正整数q (q<=1,000,000),接下来q行每行三个非负整数m, k, s (1<=m<=10^9, 1<=k<=100,000, 0<=s<=10^9)。

Output
输出q行,每行为TAK (yes)或NIE (no),第i行对应第i此询问的答案。

Sample Input
5
6 2 7
5 4 9
1 2 4
2 5 8
1 3 9
5
2 7 1
2 7 2
3 2 0
5 7 2
4 1 5
Sample Output
TAK
NIE
TAK
TAK
NIE

题解:这题Bzoj已经没了??,我只能复制大犇的题目。这道是一道很不错的思维dp题。看到题目的三个限制,第一时间要想到讲他们分开来处理,c<=1000这个很明显是一个突破口。然后看a和b,单看a而言,可以想到用离线操作。但是b怎么处理呢。可以观察到题目只问是否可行,我们可以弄一个数组记录的是可以达到这个状态的最大值,这样对于每个询问我们只要判断一下,最大值是不是大于m+s就好了

贴一份没有办法检测是否ac的代码

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=1e3+5;
const int Maxn=1e6+5;
struct node{
	int a,b,c;
	bool operator <(const node&A)const{
		return a<A.a;
	}
}w[maxn];
struct Node{
	int m,s,k,id;
	bool operator <(const Node&A)const{
		return m<A.m;
	}
}q[Maxn];
int f[Maxn];
bool ans[Maxn];
int main()
{
	int n,Q;
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
		scanf ("%d%d%d",&w[i].a,&w[i].b,&w[i].c);	
	sort(w+1,w+1+n);
	scanf("%d",&Q);
	for (int i=1;i<=Q;i++)
		scanf("%d%d%d",&q[i].m,&q[i].k,&q[i].s);
	sort(q+1,q+1+Q);
	memset(f,0,sizeof(f));
	int index=0;
	f[0]=1e9+5;
	for (int i=1;i<=Q;i++)
	{
		while (index+1<=n&&w[index+1].a<=q[i].m)
		{
			index++;
			for (int j=0;j<=100000-w[index].b;j++)
				f[j+w[index].b]=max(f[j+w[index].b],min(f[j],w[index].b));
		}
		if (f[q[i].k]>q[i].m+q[i].s)
			ans[q[i].id]=1;
		else ans[q[i].id]=0;
	}
	for (int i=1;i<=Q;i++)
		if (ans[i]) printf("TAK\n");
		else printf("NIE\n");
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值