【POI2012】SZA-Cloakroom

题面

链接在这里(洛谷)
bzoj上是权限题哇qwq
简述题意:
n(1<=n<=1000)件物品,每件物品有三个属性c[i],a[i],b[i](1<=c[i]<=1000,1<=a[i]<b[i]<=109)
再给出q(q<=106)个询问,每个询问由非负整数m,k,s(1<=m<=109,1<=k<=105,0<=s<=109)组成,问是否能够选出某些物品使得:ia[i]<=mb[i]>m+sc[i]=k

分析

最开始考虑的是限制条件对应一个二维线段树的区间,但是想了想好想不太能搞,合并的复杂度有点上天。
那么首先考虑退化退化版本,没有a[i]b[i]的限制,那么明显是一个可达性dp
继续考虑退化版本,如果只有a[i]的限制怎么处理。
注意到一般的可达性dp中从未利用过物品的访问顺序,于是我们考虑将物品按照a[i]排序,当访问到一个a[i]的时候就把恰好大于他的询问都处理。
现在需要考虑怎么加入另一个限制。其实我们只需求一个不用离线排序的做法做刚刚那个退化问题,然后结合刚刚算法就可以了。
注意到我们另一个用的不太充分的东西是dp[i],一般的可达性dp中dp[i]01,利用效率不高。于是令dp[i]表示拼出i的数值的所有方案中,最小的b[i]最大能是几,于是我们只需在询问的时候去看dp[i]是否大于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;
}
posted @ 2018-08-18 14:44  hychyc1  阅读(76)  评论(0编辑  收藏  举报