首页 > 其他分享 >杂题选做

杂题选做

时间:2023-08-19 10:22:19浏览次数:28  
标签:node cng int back tim ans 杂题

\(CF1839E\) Decreasing Game

考虑两个数的情况。显然,若两数不等,先手胜;否则,后手胜。

不妨直接猜结论 : 如果能找出一个集合,使得集合中元素的和恰为总和的一半, 则后手胜; 否则先手胜。

充分性很显然,每次先手选择一个数,后手只要在另一个集合中也选一个数即可。 这样两个集合减少的值相同;

需要证明的是如果找不出这样一个集合,那么是否经过若干次操作后,仍然找不出。

若一次操作两人分别选择了 \(x\) 和 \(y\) 且 \(x \leq y\), 假设经过这次操作后可以找出一个集合,使得其元素和为总和一半,其中 \(y - x\) 所在集合的其他数总和为 \(s1\),

另一个集合总和为 \(s2\),即 \((y - x) + s1 = s2\), 移项后发现 \(y + s1 = x + s2\), 矛盾。

因此结论是成立的。

用动态规划求解一个背包问题即可。

时间复杂度 \(O(N ^ 3)\)

\(CF1748E\)

首先发现,一个序列合法当且仅当大小关系和原序列一致。

建出笛卡尔树后解一个简单的动态规划 , 即可。

时间复杂度 \(O(NM)\)

\(CF1858E\)

不妨考虑如果不支持回退怎么做。

考虑这些 \(+\) 和 \(-\) 的操作其实可以抽象为一个树形结构。 对于每个点而言,根到其路径上的数可以还原原序列是什么样子。

假设上次操作结束后所在的点为 \(u\), 如果添加一个数, 那么新建一个点 \(v\) 作为 \(u\) 的儿子即可。如果将序列长度减少 \(k\), 那么相当于往父亲方向跳了 \(k\) 次。

所以可以通过倍增实现求 \(k\) 级祖先。

而如果有回退怎么办呢?直接维护一个栈,栈里存储每次操作后当前点的位置。 每次回退弹出栈顶即可。

现在唯一的问题是如何求答案?

最简单的方式是将所有询问离线, 用一次 \(DFS\) 可以很方便求出每个点到根路径上不同的数的个数。

这样做可以轻松通过 \(E1\), 而无法通过 \(E2\), 因为 \(E2\) 强制在线。

不难发现这个祖先-后代的关系其实可以用可持久化线段树维护。 对于每个添加操作,只需要在线段树上查一查,看看能不能产生贡献即可。

这样做时间复杂度是 \(O(NlogN)\) 的, 足够通过本题。

然而我们有更优秀的线性做法 :

考虑一个数对答案有贡献,当且仅当它首次出现。

维护一个长度为 \(n\) 的数组 \(a\), 和一个长度为 \(N\) 的数组 \(A\) 其中 \(n \leq N\),并且 \(\forall i \leq n, a_{i} = A_{i}\)。另外记 \(occ_{i}\) 表示 \(i\) 这个数第一次

出现是在什么位置。我们只需要保证对于每个 \(a_{i}\),\(occ_{a_{i}}\) 的值是正确的。

如果新添加一个数 \(x\),如果 \(occ_{x} > n\) 或者 \(a_{occ_{x}} \neq x\),那么可以更新 \(occ_{x}\) 的值,并将答案加一。

如果将序列长度减少 \(k\), 那么直接将 \(n\) 减去 \(k\) 。

对于回退操作, 我们像刚才描述的一样, 用堆栈记录更新操作。 每次取栈顶即可。

而对于求答案, 维护一个数组 \(ans\), 要求的就是 \(ans_{n}\)

时间复杂度 \(O(N)\)

放一下代码

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;

const int MN = 2e6 + 5;

struct node {
    int *x, val;
    node(int *x, int val) : x(x), val(val) {}
} ;

int foo[MN], ans[MN], a[MN], tim;
char c[2];
stack < vector < node > > s;

int main() {

    int q; scanf("%d", &q);
    while (q--) {
        scanf("%s", c);
        if (c[0] == '+') {
            vector < node > cng;
            int x; scanf("%d", &x);
            if (foo[x] > tim || a[foo[x]] != x) {
                cng.emplace_back(node(&foo[x], foo[x]));
                foo[x] = tim + 1;
                cng.emplace_back(node(&ans[tim + 1], ans[tim + 1]));
                ans[tim + 1] = ans[tim] + 1;
            } else {
                cng.emplace_back(node(&ans[tim + 1], ans[tim + 1]));
                ans[tim + 1] = ans[tim];
            }
            cng.emplace_back(node(&a[tim + 1], a[tim + 1]));
            a[tim + 1] = x;
            cng.emplace_back(node(&tim, tim));
            ++tim;
            s.push(cng);
        } else if (c[0] == '-') {
            vector < node > cng;
            int x; scanf("%d", &x);
            cng.emplace_back(node(&tim, tim));
            tim -= x;
            s.push(cng);
        } else if (c[0] == '!') {
            vector < node > v = s.top(); s.pop();
            for (node e : v)
                *e.x = e.val;
        } else {
            printf("%d\n", ans[tim]);
            fflush(stdout);
        }
    }
    return 0;
}

标签:node,cng,int,back,tim,ans,杂题
From: https://www.cnblogs.com/evenbao/p/17642127.html

相关文章

  • 【杂题乱写】USACO 2022 DEC
    BronzeT1CowCollege暴力扫一遍,更新最大值。提交记录:Submission-LuoguT2FeedingtheCows贪心放,维护一个能分别被\(\texttt{G}\)和\(\texttt{H}\)覆盖到的最远位置,如果当前位置\(i\)覆盖不到就在\(i+k\)放一个新的。由于\(i\)各不相同,这样放置除了可能在\(n\)......
  • CF杂题选刷
    CF1855BLongestDivisorsInterval对于任意一个区间\(\left[l,r\right]\),一定有\(\foralli\in\left[1,r-l+1\right]\),都\(\existsj\in\left[l,r\right]\),使得\(i\midj\)。因为模\(i\)意义下的正整数每\(i\)个一循环,由于\(i\)小于区间长度,所以在这个......
  • 杂题题解
    UOJ21缩进优化题目链接记\(M=\max(a_i)\)从反面考虑,考虑\(x\)让答案减小的量。即为$\sum_{i=1}^n\lfloor\frac{a_i}{x}\rfloor\times(x-1)=(x-1)\sum_{i=1}^n\lfloor\frac{a_i}{x}\rfloor$。只需要快速计算$S=\sum_{i=1}^n\lfloor\frac{a_i}{x}\rfloor$。可以......
  • Atcoder杂题笔记
    大概会把博客当草稿纸用(当然写出正解还是会把正解贴出来。[ARC080E]YoungMaids(待补代码)给定正偶数\(N\)。给定\(N\)元排列\(p=(p_1,p_2,...,p_N)\).Snuke打算根据下述步骤构造一个\(N\)元排列\(q\)。首先,令\(q\)为空。接下来,执行下述操作直到\(p\)为空......
  • 杭电多校 2023 杂题题解
    打算只写点有意思的题。D1JEasyproblemI注意到\(x_i\)单增,所以一个数被减到负数之后,所有的操作都会将它减到负数,也就等价于乘\(-1\)再相加。使用一棵线段树维护所有数,将这些数分为两种,一种如上,一种是区间减。最终所有数都会变为需要乘\(-1\)再相加的数,于是只要每次精......
  • 杂题
    洛谷博客已隐藏,没有投洛谷题解的题解。by0htoAiLOJ#3188无人驾驶出租车可以用线段树维护每行每列的最后一次操作的时刻。对于一个询问,容易得到哪些行列是可以走的。就三种情况,要不然一横一竖各过一个点。答案为理论最小。要不然两横过两个点,通过一竖传递,要不然两竖过两个点,......
  • 8月杂题[距离最后一场 CSP-S 还有 3 个月]
    Cu傻逼来写自己最后一个赛季的第一篇博客啊。1.CF1225GToMake1直接dp复杂度寄了啊,考虑找点性质。有解的必要条件就是存在一组\(x_i\)使得\(\sum\frac{a_i}{k^{x_i}}=1\)对吧,其中\(x_i\)可以看作是一个数在合并过程中被除的次数。这个其实就是充分的啊。考虑设......
  • 2023.8.4 杂题
    1.P5344【XR-1】逛森林先用并查集维护连通性。考虑如何建立传送门:如果使用树剖,强行线段树优化建图,那么空间开销过大,已经有2只\(\log\)。考虑使用倍增优化建图,对于一个点向上\(2^k\)的祖先的形成链都建一个点,模仿LCA的过程建边,空间是1只\(\log\).如果我们模仿ST......
  • 杂题
    题意给定\(n\)个元素的序列\(\{a_i\}\),\(m\)个元素的序列\(\{b_i\}\),以及\(L\),求:\(\sum\limits_{i=1}^n\sum\limits_{j=1}^m\sum\limits_{k=1}^L\lceil\frac{a_i+b_j}{k}\rceil\)\(n,m\le1000\)\(a_i、b_i\in[1,10^9]\)\(L\in[1,2\times10^9]\)做......
  • 2023暑假集训杂题
    2023暑假集训杂题解题报告UOJNOIRound#7Day1那些你不要的题目链接题目描述给定长度为\(n\)的序列\(A\),保证\(n\)为奇数,你是先手,每次先手与后手分别取相邻的\(2\)个数,并将剩下的数合并。先手希望最后剩下的数最大,后手希望剩下的数最小,在最优策略下,最后剩下的数是多......