P3586 POI2015 Logistyka

P3586 POI2015 LOG - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

先简单 hack 一下操作二和 acs\sum a \ge cs 等价这种错解:a=(1,1,4)a = (1, 1, 4) 无法完成 c=3,s=2c = 3, s = 2

运用P5815 CQOI2010 扑克牌的思想,我们可以将每轮操作二看成:

第一步:给 aa 中不同的 ncn - c 个数 +1+ 1;第二步:给 aa 中所有的数 1-1,判断是否保证每轮是否都够减。

然后分解,考虑先进行 ss 轮第一步,再进行 ss 轮第二步(因为第二步的操作永远是固定的)。

就成功把操作二转化为,能否操作 ss 轮,每轮可以使 aa 中不同的 ncn - c 个数 +1+1。最终让每个数都达到 ss

容易想到,每轮我们选择 aa 中最小的 ncn - c 个将它们 +1+1 是非常优秀的。

考虑证明,设 p=aissaip = \sum\limits_{a_i \le s}s - a_i,其含义为每个小于等于 ss 的数补到 ss 需要被 +1+1 的次数总和。

显然 p>s(nc)p > s(n - c) 时一定无解。

ps(nc)p \le s(n - c) 时,初始的 00 的数量一定不超过 ncn - c,因此我们第一轮选数一定会把所有的 00 选上并把它们 +1+1,第一轮后 aa 的最小值一定大于等于 11。而第一轮后 aa11 的数量一定也不超过 ncn - c,否则同样和 ps(nc)p \le s(n - c) 矛盾,所以第二轮选数会选中所有的 11,第二轮后 aa 的最小值一定大于等于 22……因此第 ss 轮后 aa 的最小值一定大于等于 ss

更严谨的说明

因此操作二和判断 ps(nc)p \le s(n - c) 等价。其中,c,s,nc, s, n 都是已知的参数,pp 就是我们维护的内容。


因此原问题可以简化成:维护一个支持单点修改的序列,支持查询 p=aissaip = \sum\limits_{a_i \le s}s - a_i

思考查询内容的本质:小于等于 ssaia_i 中,sais - a_i 的总和。容易发现,设 ff 是小于 ss 的数的数量,gg 是小于 ss 的数的和,pp 可以改写为 fsgfs - g。而 ffgg 可以用两个权值树状数组分别快速维护。

具体来说,t[x]t[x] 存储值为 xxaia_i 的数量,t2[x]t2[x] 存储值为 xxaia_i 的总和,那么 ff 可以通过查询 tt[1,s][1, s] 的前缀和得到,gg 可以通过查询 t2t2[1,s][1, s] 的前缀和得到。最后,t1,t2t1, t2 使用下标离散化和树状数组优化加速。

时间复杂度 O(mlogm+mlogn)\mathcal{O}(m \log m + m \log n),需要离线(离散化需要)。


bonus:操作二的另一种处理思路,最后得到的式子是一样的。

/*
 * @Author: crab-in-the-northeast 
 * @Date: 2022-10-25 10:17:19 
 * @Last Modified by: crab-in-the-northeast
 * @Last Modified time: 2022-10-25 18:00:46
 */
#include <bits/stdc++.h>
#define int long long
inline int read() {
    int x = 0;
    bool flag = true;
    char ch = getchar();
    while (!isdigit(ch)) {
        if (ch == '-')
            flag = false;
        ch = getchar();
    }
    while (isdigit(ch)) {
        x = (x << 1) + (x << 3) + ch - '0';
        ch = getchar();
    }
    if(flag)
        return x;
    return ~(x - 1);
}
inline char rech() {
    char ch = getchar();
    while (!isalpha(ch))
        ch = getchar();
    return ch;
}

inline int lowbit(int x) {
    return x & (-x);
}

const int maxn = (int)1e6 + 5;
const int maxm = (int)1e6 + 5;

int typ[maxm], op1[maxm], op2[maxm];

int ua[maxn];

struct fenwick {
    int c[maxn], n;

    inline void add(int x, int v) {
        for (; x <= n; x += lowbit(x))
            c[x] += v;
    }

    inline int get(int x) {
        int ans = 0;
        for (; x; x -= lowbit(x))
            ans += c[x];
        return ans;
    }
} t1, t2;

int a[maxn];

int *en;

inline int lsh(int x) {
    return std :: lower_bound(ua + 1, en, x) - ua;
}

signed main() {
    int n = read(), m = read();

    ua[1] = 0;
    for (int i = 1; i <= m; ++i) {
        char ch = rech();
        typ[i] = (ch == 'U' ? 1 : 2);
        op1[i] = read();
        op2[i] = read();
        ua[i + 1] = op2[i];
    }

    std :: sort(ua + 1, ua + m + 2);
    en = std :: unique(ua + 1, ua + m + 2);

    t1.n = t2.n = m + 1;
    t1.add(lsh(0), n);
    for (int i = 1; i <= m; ++i) {
        if (typ[i] == 1) {
            int x = op1[i], v = op2[i];
            int lax = lsh(a[x]), lv = lsh(v);
            t1.add(lax, -1);
            t2.add(lax, -a[x]);
            a[x] = v;
            t1.add(lv, 1);
            t2.add(lv, v);
        } else {
            int c = op1[i], s = op2[i], ls = lsh(s);
            int f = t1.get(ls), g = t2.get(ls);
            puts(f * s - g <= s * (n - c) ? "TAK" : "NIE");
        }
    }

    return 0;
}
posted @   dbxxx  阅读(65)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
历史上的今天:
2020-10-25 [CF1436A] Reorder
点击右上角即可分享
微信分享提示