@dxbdly
2023-01-28T15:38:23.000000Z
字数 4555
阅读 156
2023冬
预期得分:
| T1 | T2 | T3 | Sum |
|---|---|---|---|
| 100 | 100 | 50 | 250 |
实际得分:
| T1 | T2 | T3 | Sum |
|---|---|---|---|
| 30 | 100 | 10 | 140 |
T1: 考场上数组开小了,挂成30分
T2: 考场AC
T3: 考场上的时候想到了大致的维护策略,却执着于将线段树二分与修改放在一起写,增加了很多代码细节,导致没写出来。
涉及算法/想法:异或,构造
思维难度:
代码难度:
上了大学之后,小W 和 小Z 一起报了一门三宝课,在实践课上遇到了一些问题。
一条染色体上有 对基因,每种基因都可以用一个数 来表示,作为标号。
现在,在其中一条染色单体上某基因发生了突变。
此时染色体上有 对相同的基因和一对不同的基因。
他们通过某种方法获得了这条染色体上的全部基因。
现在他们想知道发生突变的基因的标号是什么。
想法非常神奇的一道题目。
我们考虑用一个长度为 的容器解决问题。
我们将容器分成两部分,将 二进制分解,将为 的第 位异或上 ,将为 的第 位异或上
此时,除了要求的两个数外,其他的数的贡献一定会消除,并且,容器中必定会剩下 个数,,,^
并且将所有数直接异或起来就可以得到 ^,则可以得到 ,
//The Code Is By HJC# include <cstdio># define max(a, b) (a>b?a:b)# define min(a, b) (a<b?a:b)// # define N 1001000using namespace std;int n;// int a[N];int f[70], ban;int main() {// freopen("human.in", "r", stdin);// freopen("human.out", "w", stdout);scanf("%d", &n);for (int i = 1, a; i <= n + n; i++) {scanf("%d", &a);ban ^= a;for (int i = 0; i < 32; i++) {if ((a >> i) & 1) {f[i] ^= a;} else {f[i + 32] ^= a;}}}int ans1 = 0, ans2 = 0;for (int i = 0; i < 64; i++) {if (f[i] && f[i] != ban) {if (ans1 == 0) {ans1 = f[i];} else if (f[i] != ans1) {ans2 = f[i];break;}}}printf("%d %d\n", min(ans1, ans2), max(ans1, ans2));}
涉及算法/想法:前缀和,鸽巢原理
思维难度:
代码难度:
上了大学之后,小W 和 小Z 一起报了一门水课,在做作业时遇到了问题。
有一个长度为 的数列 ,为一列树木的美观值。
现在有 次询问,每次给出三个数 , 和
询问对于所有的
的最小值。
先转化成前缀和
则我们希望,
长度如果超过 ,则必定有
那么最多只有长度为 的区间是有用的,这部分暴力即可。
//The Code Is From Dawn#include<bits/stdc++.h>#define int long longusing namespace std;inline int read() {int x = 0;char c = getchar();bool f = 0;while(!isdigit(c)) f |= (c == '-'), c = getchar();while(isdigit(c)) x = (x * 10) + (c ^ 48), c = getchar();return f ? -x : x;}const int maxn = 5 * 1e4 + 5;int n, Q, T;int a[maxn], Answer;struct node {int l, r, id;};signed main() {freopen("garden.in", "r", stdin);freopen("garden.out", "w", stdout);n = read(), Q = read();for(register int i = 1; i <= n; ++i) a[i] = read();while(Q--) {int il = read(), ir = read(), mod = read();if(ir - il + 1 > mod) { printf("0\n"); continue; }Answer = 1e9 + 7;for(register int l = il; l <= ir; ++l) {int Cnt = 0;for(register int r = l; r <= ir; ++r) {Cnt = (Cnt + a[r]) % mod;Answer = min(Answer, Cnt);}}printf("%lld\n", Answer);}return 0;}
涉及算法/想法:线段树,线段树二分
思维难度:
代码难度:
给定 个三元组 ,要求分到 个集合 , , 中,每个集合的价值是三元组中对应元素的最大值,要求三个集合价值之和最小。
考虑枚举 ,计算
容易得到一个 的做法。
发现每次重新排序太冗余,考虑将 的枚举倒过来,则每次只需要加入一个双元组 。
考虑他对后半段答案的影响。
我们可以将答案表示为 其中 为 的后缀最大值。
那么只有在 的区间中,满足 的子区间会被影响到,并且是一个区间推平的操作。
那么考虑维护一颗线段树,每次线段树上二分出子区间的左端点,将子区间做区间推平,顺便维护答案即可。
//The Code Is From Dawn#include<bits/stdc++.h>#define int long longusing namespace std;inline int read() {int x = 0;char c = getchar();bool f = 0;while(!isdigit(c)) f |= (c == '-'), c = getchar();while(isdigit(c)) x = (x * 10) + (c ^ 48), c = getchar();return f ? -x : x;}const int maxn = 1e5 + 5, INF = 1e9 + 7;int n, Answer;struct node {int a, b, c;}Point[maxn];int ls[maxn], tot;namespace Sigment_Tree {struct node_Tree {int Suf, minn;int lz;}Tree[maxn << 2];#define lc(i) i << 1#define rc(i) i << 1 | 1inline void Push_Up(int i) {Tree[i].Suf = min(Tree[lc(i)].Suf, Tree[rc(i)].Suf);Tree[i].minn = min(Tree[lc(i)].minn, Tree[rc(i)].minn);}inline void Build(int i, int l, int r) {Tree[i].Suf = 0;if(l == r) { Tree[i].minn = ls[l]; return ; }int mid = (l + r) >> 1;Build(lc(i), l, mid), Build(rc(i), mid + 1, r);Push_Up(i);}inline void Push_Down(int i, int l, int r) {int mid = (l + r) >> 1;if(Tree[i].lz) {Tree[lc(i)].Suf = Tree[rc(i)].Suf = Tree[i].lz;Tree[lc(i)].lz = Tree[rc(i)].lz = Tree[i].lz;Tree[lc(i)].minn = Tree[i].lz + ls[l];Tree[rc(i)].minn = Tree[i].lz + ls[mid + 1];Tree[i].lz = 0;}}inline void Update(int i, int l, int r, int ql, int qr, int num) {if(l >= ql && r <= qr) {Tree[i].minn = num + ls[l];Tree[i].lz = Tree[i].Suf = num;return ;}Push_Down(i, l, r);int mid = (l + r) >> 1;if(ql <= mid) Update(lc(i), l, mid, ql, qr, num);if(qr > mid) Update(rc(i), mid + 1, r, ql, qr, num);Push_Up(i);}inline int Find(int i, int l, int r, int num) {Push_Down(i, l, r);if(l == r) return l;int mid = (l + r) >> 1;if(Tree[lc(i)].Suf <= num) return Find(lc(i), l, mid, num);else return Find(rc(i), mid + 1, r, num);}}using namespace Sigment_Tree;signed main() {freopen("psy.in", "r", stdin);freopen("psy.out", "w", stdout);n = read();for(register int i = 1; i <= n; ++i) {Point[i].a = read();ls[++tot] = Point[i].b = read();Point[i].c = read();}sort(ls + 1, ls + tot + 1); tot = unique(ls + 1, ls + tot + 1) - ls - 1;for(register int i = 1; i <= n; ++i) Point[i].b = lower_bound(ls + 1, ls + tot + 1, Point[i].b) - ls;sort(Point + 1, Point + n + 1, [&](node x, node y){ return x.a < y.a; });Answer = Point[n].a, Build(1, 0, tot);for(register int i = n - 1; i >= 0; --i) {int pos = Find(1, 0, tot, Point[i + 1].c);Update(1, 0, tot, pos, Point[i + 1].b - 1, Point[i + 1].c);Answer = min(Answer, Point[i].a + Tree[1].minn);}printf("%lld\n", Answer);return 0;}