链接:https://www.luogu.org/problemnew/show/P3537
有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。
输入输出格式
输入格式:
n ( 1≤n≤1 000 )
Those items are described in the nn lines that follow.
c a b(1≤ci≤1 000 ,1≤ai<bi≤10e9 )
p (1≤p≤1 000 000 ),
m k s 1≤m,j≤10^9 , 1≤kj, sj≤100 000
输出格式:
For each plan put forward by the gang determine if it is feasible, i.e., whether it is possible to steal items of total worth exactly k_jkj and escape before anyone asks for their belongings.
If the plan is feasible, your program should print the word TAK (Polish for yes) on the standard output, otherwise it should print NIE (Polish for no).
输入输出样例
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
TAK NIE TAK TAK NIE
题解:离线
我们把所有的 mm 和所有的ai 从小到大排序,然后就是一个背包问题了,因为这样我们做到一边把物品放入背包一边去处理这个询问。
定义fi 表示当物品的和为 i 时在所有的方案中,使得最小的 b 最大的方案中的 b 值。(这话有些绕口)
然后接下来我们只要判断一下 fi 是否大于m+s 即可。
注意边界问题,我开始漏算了M巨大时的情况,和今天早上一样算了还=后面一截
#include<bits/stdc++.h> using namespace std; const int N = 1005, M = 1000005; #define For(a, b, c) for(int a = b; a <= c; a++) struct Point{int a, b, c;}p[N]; struct Query{int m, s, k, id;}q[M]; bool cmp1(Point A, Point B){ return A.a < B.a; } bool cmp2(Query A, Query B){ return A.m < B.m; } int ans[M], dp[M]; int main(){ //freopen("dt.in","r",stdin); //freopen("my.out","w",stdout); int m, n; scanf("%d", &n); For(i, 1, n)scanf("%d%d%d", &p[i].c, &p[i].a, &p[i].b); sort(p+1, p+1+n, cmp1); scanf("%d", &m); For(i, 1, m)scanf("%d%d%d", &q[i].m, &q[i].k, &q[i].s), q[i].id = i; sort(q+1, q+1+m, cmp2); dp[0] = 1e9 + 100; int nlst = 1, lst = 1; int limit = q[1].m; p[n+1].a = dp[0]; bool fg = 0; int j; for(int i = nlst; i <= n;){ //cout<<i<<" "<<nlst<<endl; while(p[i].a <= limit){ for(int j = 100000; j >= p[i].c; j--) dp[j] = max(dp[j], min(dp[j - p[i].c], p[i].b)); i++; } nlst = i; for( j = lst; q[j].m == q[lst].m; j++){ int id = q[j].id; if(q[j].m + q[j].s < dp[q[j].k])ans[id] = 1; //else ans[id] = -1; } lst = j; limit = q[lst].m; if(lst == m + 1)break; //fprintf(stderr, "%d ", lst); } for( ; j <= m; j++) if(dp[q[j].k] > q[j].m + q[j].s)ans[q[j].id] = 1; for(int i = 1; i <= m; i++) if(ans[i] == 1)puts("TAK"); else puts("NIE"); }