【POI2012】SZA-Cloakroom

题面

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

分析

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

猜你喜欢

转载自blog.csdn.net/hychxb/article/details/81808707