• 题解 P3545 【[POI2012]HUR-Warehouse Store】


    P3545 [POI2012]HUR-Warehouse Store

    Describe

    一共 (n) 天,每天上午会进 (A_i) 的物品,中午会有一个客人想要买走 (B_i) 的物品,当然你也可以选择不买,问你最后最多可以交易多少次。

    数据范围 : (1 <= n <= 250000, 0 <= A_i, B_i <= 10^9)

    Solution

    首先,我们看到题目先会想到 (01) 背包。是个正确的作法,但是肯定过不了。

    然后,我们考虑到这一定是个贪心/推式子的题目。

    但是推式子的题目一般的特性在这里显然不符合(推式子的题目一般不会让你选择)


    那接下来考虑怎么去贪心。

    第一想法是我们选最小的肯定是最优的,因为就算选了这个最小的而导致其他的不可以选,那也最多只能导致一个不可以选。

    因为如果可以导致多个不可以选的话,选了次小的哪一个也会导致更多的不可以选。

    所以选择最小的策略是对的,(sort) 一般的复杂度我们也可以接受,但是问题来了,我们那些数可以取?

    取完当前最小的,那么它前面的一些数说不定不可以再去。

    那么处理这些的复杂度就不稳定了,可以构造数据卡掉。


    接下来我们想每天上午进的货物会对什么有影响。

    这个很显然,它可以对他后面的所有数产生影响,因为到货了就可以卖给别人了。

    那是不是可以这么考虑,从后往前去跑,每次去当前可以取的最小的。

    因为从后完全就去除了它的后效性,所有正确性也是对的。

    但是新增一个数 (A_i) 可能很大,一次可以处理多个数。

    那你就必须保证后面整个序列是有序的,而且还要维护一个后缀和。

    我们考虑维护这个有序数列的复杂度最优,那就是往前加一个数,就把这个数加入到数列里面去。

    这样的复杂度最劣是 (O(n^2)) 的,还是会炸。


    那我们是不是无法从一些顺序上去找到优化的空间。

    我们就可以考虑去莽,然后支持撤销,这样也可以保证正确性。

    具体的话是这样实现的:

    从前往后读入,每次可以取就取,并且把这些取过的记录在单调队列中。

    如果当前这个放不下,我们就把他和队列首的元素做比较,不断更新即可。

    根据我们的第二个想法,每个前面取过的如果弹出来,因为他的后效性,肯定是可以服务后面的。

    那么就结束了。

    Code

    #include <bits/stdc++.h>
    using namespace std;
    #define int long long
    const int maxn = 250010;
    int n, sum, ans, book[maxn];
    priority_queue<pair<int, int>, vector<pair<int, int> > > Q;
    struct node {
        int a, b, id;
    } e[maxn];
    int cmp(node x, node y) {
        return x.b < y.b;
    }
    signed main() {
        scanf("%lld", &n);
        for(int i = 1; i <= n; ++ i) {
            scanf("%lld", &e[i].a);
            e[i].id = i;
        }
        for(int i = 1; i <= n; ++ i) {
            scanf("%lld", &e[i].b);
        }
        for(int i = 1; i <= n; ++ i) {
            sum += e[i].a;
            if(e[i].b < sum) {
                Q.push(make_pair(e[i].b, e[i].id));
                ++ ans;
                book[i] = 1;
                sum -= e[i].b;
            }
            else if(! Q.empty() && Q.top().first > e[i].b) {
                book[Q.top().second] = 0;
                book[i] = 1;
                sum += e[Q.top().second].b - e[i].b;
                Q.pop(); Q.push(make_pair(e[i].b, e[i].id));
            }
        }
        printf("%lld
    ", ans);
        for(int i = 1; i <= n; ++ i) {
            if(book[i]) {
                printf("%d ", i);
            }
        }
        return 0;
    }
    

    Ps:本人知道题解前不应该放错误作法,但是觉得这些错误作法也是一些解题的思路,这里用不上,其他地方可能用到上,望批准。

  • 相关阅读:
    System.web和System.WebServer
    Clone Detective java home
    2008年国外最佳Web设计/开发技巧、脚本及资源总结
    Multiview + UserControl 中UserControl如何判断首次执行
    .NET必看的几个网站
    深入剖析ASP.NET的编译原理之一:动态编译(Dynamical Compilation)(转)
    SQL Server 阻止了对组件 \'Ad Hoc Distributed Queries\' 的访问
    SQL SERVER 建表的限制
    dll文件
    com组件ConvertStringToBSTR(转)
  • 原文地址:https://www.cnblogs.com/Flash-plus/p/13836226.html
Copyright © 2020-2023  润新知