首页 > 其他分享 >P8350 [SDOI/SXOI2022] 进制转换

P8350 [SDOI/SXOI2022] 进制转换

时间:2024-01-30 12:12:20浏览次数:29  
标签:cnt SDOI SXOI2022 int P8350 len ++ del mathcal

记 \(len_x\) 为 \(x\) 在 \(a\) 中出现的次数,显然有 \(\mathcal O(nq)\) 的暴力,拿下 \(20\) 分。

感觉用数据结构难以维护,考虑根号做法。

根号做法有一个阈值 \(L\),然后分讨(钦定 \(len_x \le len_y\)):

  • \(len_x \le len_y \le L\)

直接暴力做,时间复杂度 \(\mathcal O(L)\)。

  • \(L < len_x \le len_y\)

这样的 \(x, y\) 有 \(\mathcal O(\dfrac{n^2}{L^2})\) 种,做一次的时间复杂度是 \(\mathcal O(L)\),预处理的时间复杂度是 \(\mathcal O(\dfrac{n^2}L)\),此后 \(\mathcal O(\log L)\) 查询就好了(map)。

  • \(len_x \le L < len_y\)

只有 \(\sum\limits_{i = l}^r c_i = 0\) 的区间才对答案有贡献,显然有不少无用的 \(y\)。

我们对每个 \(x\) 在左右各保留 \(2\) 个 \(y\),不难发现这样的序列和原序列等价,用 set 转化然后暴力做,单次时间复杂度是 \(\mathcal O(L \log n)\),总时间复杂度就是 \(\mathcal qL \log n\)。

为什么要两个 \(y\)?

每个 \(x\) 只能向左或向右匹配一个 \(y\),但是如果只保留一个 \(y\) 的话,会出现这样的情况:

yyxxyyyyyyyyyyxxyy 变为了 yyxxyyxxyy,原序列上最长只能选到 xxyy,但新序列上最长能选到 xxyyxxyy

这启示我们 \(y\) 还具有分割作用,所以再多保留一个 \(y\) 即可。

忽略小的时间复杂度,由均值不等式得 \(\dfrac{n^2}L + qL \log n \ge 2n\sqrt{q \log n}\),当且仅当 \(L = \dfrac{n^2}{q \log n}\) 时取等。

于是时间复杂度就是 \(\mathcal O(n \sqrt{q \log n})\)。

代码:

#include <bits/stdc++.h>

using namespace std;

typedef pair<int, int> pii;
typedef long long ll;

constexpr int N = 3e5 + 10, L = 500;
constexpr ll inf = 9e18;

int n, q, b[N];

vector<int> p[N];
set<int> s[N];

namespace SS {
    int cnt, a[N], c[N];
    unordered_map<int, ll> mn;

    ll solve(int x, int y) {
        cnt = 0; int i = 0, j = 0;
        while (i < p[x].size() && j < p[y].size()) {
            cnt++;
            if (p[x][i] < p[y][j]) a[cnt] = p[x][i++], c[cnt] = 1;
            else a[cnt] = p[y][j++], c[cnt] = -1;
        }
        while (i < p[x].size()) a[++cnt] = p[x][i++], c[cnt] = 1;
        while (j < p[y].size()) a[++cnt] = p[y][j++], c[cnt] = -1;
        int s = 0; ll sum = 0, ans = -inf;
        mn.clear(), mn[0] = 0;
        for (int i = 1; i <= cnt; i++) {
            s += c[i], sum += b[a[i]];
            if (mn.find(s) != mn.end()) {
                ans = max(ans, sum - mn[s]);
                mn[s] = min(mn[s], sum);
            } else mn[s] = sum;
        }
        return ans;
    }
}

namespace BB {
    int cnt, a[N], c[N];
    map<pii, ll> mem;
    
    ll solve(int x, int y) {
        if (mem.find(pii(x, y)) != mem.end()) return mem[pii(x, y)];
        return mem[pii(x, y)] = SS::solve(x, y);
    }
}

namespace SB {
    int cnt;
    struct Node {
        int p, c;
        bool operator<(const Node &rhs) const {return p < rhs.p;}
    } a[N];

    vector<set<int>::iterator> del;
    
    unordered_map<int, ll> mn;

    ll solve(int x, int y) {
        cnt = 0;
        for (int i : p[x]) {
            a[++cnt] = {i, 1};
            auto it = s[y].upper_bound(i);
            if (it != s[y].begin()) {
                it--, del.emplace_back(it), a[++cnt] = {*it, -1};
                if (it != s[y].begin()) it--, del.emplace_back(it), a[++cnt] = {*it, -1}, it++;
                it++;
            }
            if (it != s[y].end()) {
                del.emplace_back(it), a[++cnt] = {*it, -1}; it++;
                if (it != s[y].end()) del.emplace_back(it), a[++cnt] = {*it, -1};
            }
            for (auto i : del) s[y].erase(i); del.clear();
        }
        sort(a + 1, a + cnt + 1);
        int sc = 0; ll sum = 0, ans = -inf;
        mn.clear(), mn[0] = 0;
        for (int i = 1; i <= cnt; i++) {
            sc += a[i].c, sum += b[a[i].p];
            if (mn.find(sc) != mn.end()) {
                ans = max(ans, sum - mn[sc]);
                mn[sc] = min(mn[sc], sum);
            } else mn[sc] = sum;
            if (a[i].c == -1) s[y].emplace(a[i].p);
        }
        return ans;
    }
}

int main() {
    ios_base::sync_with_stdio(0); cin.tie(nullptr), cout.tie(nullptr);
    cin >> n >> q;
    for (int i = 1, a; i <= n; i++) cin >> a, p[a].emplace_back(i), s[a].emplace(i);
    for (int i = 1; i <= n; i++) cin >> b[i];
    while (q--) {
        int x, y; cin >> x >> y;
        if (p[x].size() > p[y].size()) swap(x, y);
        if (p[y].size() <= L) cout << SS::solve(x, y) << '\n';
        else if (p[x].size() > L) cout << BB::solve(x, y) << '\n';
        else cout << SB::solve(x, y) << '\n';
    }
    return 0;
}

标签:cnt,SDOI,SXOI2022,int,P8350,len,++,del,mathcal
From: https://www.cnblogs.com/chy12321/p/17996821

相关文章

  • [SDOI2019] 移动金币(阶梯博弈)
    题面一枚金币向左移若干格等价若干个空格向右移一个金币,终状态为所有空格在最右,转换为阶梯博弈阶梯博弈每个阶梯上有若干枚石子,每次操作将同个阶梯的任意石子向下移一个阶梯,不能操作者输等价对奇数阶梯做Nim博弈先手按Nim博弈操作。若对方移动偶数阶梯,则将对方移动石子继续下......
  • P5618 SDOI2015 道路修建题解
    题目分析虽然数据范围只有\(n\le60000\),但是完全可以直接用线段树做。首先考虑那种状态的图在左边和右边加入节点和边之后可以连通。容易发现,这种图有这两个性质:至少有一条路径,经过最左端和最右端中的点。所有点至少和最左端和最右端的点连通。于是可以划分成以下几种状态......
  • P5362 [SDOI2019] 连续子序列 题解--zhengjun
    题面传送门提供一种和其他题解完全不同的解法。记\(P_0\)为题中给出的序列,\(P_1\)为\(P_0\)取反的结果。记\(S_{l\simr}\)表示\(S_lS_{l+1}\dotsS_{r}\)。方便起见,\(P\)下标从\(0\)开始,其余的串都是从\(1\)开始。这里用\(P_{0,i}=\operatorname{popcount(i)}......
  • [SDOI2017] 天才黑客
    [SDOI2017]天才黑客题目背景SD0062号选手小Q同学为了偷到SDOI7012的试题,利用高超的黑客技术潜入了SDOI出题组的内联网的中央控制系统,然而这个内联网除了配备有中央控制系统,还为内联网中的每条单向网线设定了特殊的通信口令,这里通信口令是一个字符串,不同网线的口令可能不同。这......
  • 洛谷 P5359 [SDOI2019] 染色
    洛谷传送门LOJ传送门dp好题。首先有一个显然的状态,设\(f_{i,x,y}\)为第\(i\)列上下两格的颜色分别为\(x,y\)的方案数。但是这样做时间复杂度至少为\(O(nm^2)\),无法接受。注意到全\(0\)列的转移是重复的。我们可以试着只在两个相邻非全\(0\)列转移。这样我们需......
  • 题解 [SDOI2016] 游戏
    可以看出来出题人很想出一道把李超和别的什么东西凑起来的题目,于是给了这么一个缝合怪。https://www.luogu.com.cn/problem/P4069符号有点混乱。比如箭头又可以表示路径又可以表示赋值,代入语境应该还是好理解的。看到\(a\timesdis+b\)就应激反应出来是李超了,看到\(s\to......
  • [SDOI2010] 大陆争霸
    [SDOI2010]大陆争霸屁话真多。第一眼看上去好像是最短路加了个强制拓扑。也就是说当结界还没被破坏的时候,已经到达的机器人只能干等着。在dijkstra中,机器人所在的点可以更新最短路。但拓扑图上该点的入度不为\(0\),即结界产生器没有被全部破坏时,不能入队。当炸掉一个结界......
  • [SDOI2010] 大陆争霸 题解
    [题目传送门](https://www.luogu.com.cn/problem/P2446)#解法由题可知,一个城市$u$保护城市$v$,所以建一条边$u\tov$表示城市$u$保护城市$v$,因为题目说保证有解,所以建的图一定是一个**有向无环图$DAG$**。再在此基础上求出最短路径。具体过程为设$dis_u$表示实际到达(攻破)$u$的最......
  • [SDOI2017] 树点涂色
    [SDOI2017]树点涂色题目描述Bob有一棵\(n\)个点的有根树,其中\(1\)号点是根节点。Bob在每个点上涂了颜色,并且每个点上的颜色不同。定义一条路径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色。Bob可能会进行这几种操作:1x表示把点\(x\)到根节点的路......
  • luogu P3783 [SDOI2017] 天才黑客
    题面传送门为啥大家都写两个log的线段树优化建边啊,神秘,这1log做法好想又好写捏。首先显然是可以把边看成点的,这样会变成\(O(m)\)个点和\(O(m^2)\)条边,寄。但是还没有完全寄掉,我们发现,对于原图的每个点,对于第一个跑到这个点的边暴力转移,剩下的边转移只有一个子树,否则会......