• P3537 [POI2012]SZA-Cloakroom


    链接:https://www.luogu.org/problemnew/show/P3537

    有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。

    输入输出格式

    输入格式:

    n ( 1n1 000 ) 

    Those items are described in the nn lines that follow.

    c a b(1ci1 000 ,1ai<bi10e9 )

    p (1p1 000 000 ),

    m k s 1m,j10^9 , 1kj, sj100 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).

    输入输出样例

    输入样例#1: 复制
    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
    输出样例#1: 复制
    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");
         
    }
    View Code
  • 相关阅读:
    获取某表所有列名和字段类型
    C++ 长指针与指针的区别
    C# WinForm 控件光标
    不错的UML建模工具StarUML
    给控件做数字签名之一:将控件打包为Web发布包(转)
    MsComm控件注册失败
    微软发布Microsoft图表控件
    C与C++中的宏
    WinForm DataGridView 显示行号
    C#ToString格式大全
  • 原文地址:https://www.cnblogs.com/EdSheeran/p/9483305.html
Copyright © 2020-2023  润新知