##题面
链接在这里(洛谷)
bzoj上是权限题哇qwq
简述题意:
有
n
(
1
<
=
n
<
=
1000
)
n(1<=n<=1000)
n(1<=n<=1000)件物品,每件物品有三个属性
c
[
i
]
,
a
[
i
]
,
b
[
i
]
(
1
<
=
c
[
i
]
<
=
1000
,
1
<
=
a
[
i
]
<
b
[
i
]
<
=
1
0
9
)
c[i], a[i], b[i] (1<=c[i]<=1000, 1<=a[i]<b[i]<=10^9)
c[i],a[i],b[i](1<=c[i]<=1000,1<=a[i]<b[i]<=109)。
再给出
q
(
q
<
=
1
0
6
)
q(q<=10^6)
q(q<=106)个询问,每个询问由非负整数
m
,
k
,
s
(
1
<
=
m
<
=
1
0
9
,
1
<
=
k
<
=
1
0
5
,
0
<
=
s
<
=
1
0
9
)
m, k, s(1<=m<=10^9, 1<=k<=10^5, 0<=s<=10^9)
m,k,s(1<=m<=109,1<=k<=105,0<=s<=109)组成,问是否能够选出某些物品使得:
∀
选
择
的
物
品
i
,
a
[
i
]
<
=
m
,
b
[
i
]
>
m
+
s
且
∑
c
[
i
]
=
k
\forall 选择的物品i,a[i]<=m , b[i]>m+s且\sum c[i] = k
∀选择的物品i,a[i]<=m,b[i]>m+s且∑c[i]=k。
##分析
最开始考虑的是限制条件对应一个二维线段树的区间,但是想了想好想不太能搞,合并的复杂度有点上天。
那么首先考虑退化退化版本,没有
a
[
i
]
和
b
[
i
]
a[i]和b[i]
a[i]和b[i]的限制,那么明显是一个可达性dp
继续考虑退化版本,如果只有
a
[
i
]
a[i]
a[i]的限制怎么处理。
注意到一般的可达性dp中从未利用过物品的访问顺序,于是我们考虑将物品按照
a
[
i
]
a[i]
a[i]排序,当访问到一个
a
[
i
]
a[i]
a[i]的时候就把恰好大于他的询问都处理。
现在需要考虑怎么加入另一个限制。其实我们只需求一个不用离线排序的做法做刚刚那个退化问题,然后结合刚刚算法就可以了。
注意到我们另一个用的不太充分的东西是
d
p
[
i
]
dp[i]
dp[i],一般的可达性dp中
d
p
[
i
]
只
能
是
0
或
1
dp[i]只能是0或1
dp[i]只能是0或1,利用效率不高。于是令
d
p
[
i
]
dp[i]
dp[i]表示拼出
i
i
i的数值的所有方案中,最小的
b
[
i
]
b[i]
b[i]最大能是几,于是我们只需在询问的时候去看
d
p
[
i
]
dp[i]
dp[i]是否大于
m
+
s
m+s
m+s即可。
于是我们解决了这个问题。
##思路总结
在对一个问题进行思考的时候,可以首先考虑思考他的退化版本,然后考虑我们有哪些条件/变量/性质/…应用不够充分,再思考能否加以利用解决更强的问题。
##代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <bits/stdc++.h>
#include <set>
#include <queue>
#define MAXN
#define ri register int
using namespace std;
/*有n件物品,每件物品有三个属性a[i], b[i], c[i] (a[i]<b[i])。
再给出q个询问,每个询问由非负整数m, k, s组成,问是否能够选出某些物品使得:
对于每个选的物品i,满足a[i]<=m且b[i]>m+s。
所有选出物品的c[i]的和正好是k。*/
int n, Q, dp[100050], ans[1000050];
struct node{
int a, b, c, id;
bool operator < (const node &x) const {
return a < x.a;
}
}obj[1050], q[1000050];
int main() {
scanf("%d", &n);
for(ri i = 1; i <= n; i++) scanf("%d%d%d", &obj[i].c, &obj[i].a, &obj[i].b);
scanf("%d", &Q);
for(ri i = 1; i <= Q; i++) scanf("%d%d%d", &q[i].a, &q[i].c, &q[i].b), q[i].id = i;
sort(obj+1, obj+n+1); sort(q+1, q+Q+1);
int pos = 1;
dp[0] = 2e9;
for(ri i = 1; i <= n; i++) {
//cout<<obj[i].a<<' '<<obj[i].b<<' '<<obj[i].c<<'\n';
while(q[pos].a < obj[i].a && pos <= Q) {
//cout<<pos<<' '<<q[pos].a<<' '<<q[pos].b<<' '<<q[pos].c<<' '<<dp[q[pos].c]<<'\n';
ans[q[pos].id] = (dp[q[pos].c] > q[pos].a+q[pos].b);
pos++;
}
for(ri j = 100000; ~j; j--)
dp[j+obj[i].c] = max(dp[j+obj[i].c], min(dp[j], obj[i].b));
//for(ri j = 0; j <= 5; j++) cout<<dp[j]<<' ';
//cout<<'\n';
}
while(pos <= Q) {
//cout<<pos<<' '<<q[pos].a<<' '<<q[pos].b<<' '<<q[pos].c<<' '<<dp[q[pos].c]<<'\n';
ans[q[pos].id] = (dp[q[pos].c] > q[pos].a+q[pos].b);
pos++;
}
for(ri i = 1; i <= Q; i++) printf(ans[i]?"TAK\n":"NIE\n");
return 0;
}