1. 程式人生 > >BZOJ 2794 [Poi2012]Cloakroom(離線+背包)

BZOJ 2794 [Poi2012]Cloakroom(離線+背包)

scu line 表示 EDA zoj sca pri amp medium

2794: [Poi2012]Cloakroom

Time Limit: 20 Sec Memory Limit: 128 MB
Submit: 406 Solved: 241
[Submit][Status][Discuss]

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

HINT

題解

這題還行。

看了一會,自信滿滿,然後就死了。

離線把詢問按s排序。把每一個物品按a[i]排序。

然後dp[i]代表當c的和能湊成i時所用的物品b的最小值的最大值。

因為排序後每一個物品只需計算一次,所以復雜度沒有飛。(但至少我看來有問題)

所以對於每一個詢問,只需判斷dp[k]是否大於m+s就行了。

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<cmath>
 5 #include<algorithm>
 6 using namespace std;
 7 struct thing{
 8     int c,a,b;
 9 }g[2000];
10 struct query{
11     int l,r,k,id;
12 }q[1000100];
13 int n,t,dp[100100
],ans[1000100],mx; 14 bool cmp(thing a,thing b){ 15 return a.a<b.a; 16 } 17 bool mmp(query a,query b){ 18 return a.l<b.l; 19 } 20 int main(){ 21 scanf("%d",&n); 22 for(int i=1;i<=n;i++){ 23 scanf("%d%d%d",&g[i].c,&g[i].a,&g[i].b); 24 } 25 scanf("%d",&t); 26 for(int i=1;i<=t;i++){ 27 int s,k,m; 28 scanf("%d%d%d",&s,&k,&m); 29 q[i].l=s; 30 q[i].r=s+m; 31 q[i].k=k; 32 q[i].id=i; 33 mx=max(mx,k); 34 } 35 sort(g+1,g+1+n,cmp); 36 sort(q+1,q+1+t,mmp); 37 dp[0]=1999999999; 38 for(int i=1,now=1;i<=t;i++){ 39 while(now<=n&&g[now].a<=q[i].l){ 40 for(int j=mx;j>=g[now].c;j--){ 41 dp[j]=max(dp[j],min(dp[j-g[now].c],g[now].b)); 42 } 43 now++; 44 } 45 ans[q[i].id]=(q[i].r<dp[q[i].k]); 46 } 47 for(int i=1;i<=t;i++){ 48 if(ans[i])printf("TAK\n"); 49 else printf("NIE\n"); 50 } 51 return 0; 52 }

BZOJ 2794 [Poi2012]Cloakroom(離線+背包)