如何读对题意,如何调对代码,这些真的都是硬伤啊。。。

以后一定要一道题有两个人读题才行。

[A Accelerator]

solution

题面:给定长度为 的数组 ,对于 的所有排列 ,计算 的期望。

做法:稍微观察下每个 的贡献,就能发现求的正是 ,然后每一项可以通过组合意义得知乘上一个系数加起来。那么直接分治 算下就好了,不懂为什么启发式合并会 T?时间复杂度

[B Boring Problem]

solution

题面:ACAM 上随机游走。

做法:链剖后主元法消元。

[C Club Assignment]

solution

题面:有 个数,现要拆分成两个集合,最小化两个集合内的两两元素的异或的最小值的较小值。

做法:这等价于从小到大贪心,每次把异或和小的那个拆开来放在两边,直到不能放了。这样是 以上的复杂度。

发现这个过程类似 ,考虑搞出了最小异或生成树,那么树上有边的点肯定都不能在一个集合了,于是就直接结束了。而最小异或生成树太经典了,最简单的做法就是 加上 维护下即可。时间复杂度

[D Artifacts]

solution

题面:

做法:听说是原神题+大模拟,队友写的,我不知道。

[E Mountain]

solution

题面:

做法:

[F Fixing Networks]

solution

题面: 个点,要求构造一张图,使得每个点的度数为 ,且被分成了 个连通块。

做法:先判断 为奇数的情况,然后搞一堆完全图,最后一些点搞一个环,每个点向两边延伸,如果要求奇数度数就再向对角的点连边。这一定有解,因为度数为奇数的话点数一定为偶数,所以对角的点是惟一的。

[G Game on Sequence]

solution

题面:A 和 B 在玩一个游戏,这个游戏一开始在一根轴上有 个位置,每个位置上都有一个数,每个数的大小在 之间。游戏一开始有个小人在 这个位置上,每个人需要轮流将小人向右移动到另一个位置 上,要求 位置上的数和当前位置 上的数在二进制上最多只能有一位不同,当轮到一个人不能移动时,这个人便输掉了这轮游戏。在游戏开始之前,游戏可以重复的增加一个数放在数轴的最右边,对于每次询问需要回答谁会赢得这场游戏。(假设两人都足够聪明,会采用最优策略)

做法:容易发现只跟最右边的点有关,看下数据范围,直接暴力做就过了。时间复杂度

[H Fly Me To The Moon]

solution

题面:

做法:

[I Nim Cheater]

solution

题面: 博弈,每次可能加入一堆或撤销上一次操作。Alice 先手,但 Bob 可以先拿走若干堆石子。每堆石子都有一个代价,每次操作后,问 Bob 必胜所要花费的最小代价。

做法: 的结论告诉我们要求石子异或为 ,有撤销操作,注意到撤销仅对相邻的起效,于是无需线段树分治,可以直接搞出一棵树。设 表示异或为 时的最大代价,每个点的答案是它到根的路径上的 值。直接暴力则要求每个点求一遍,空间复杂度是 。考虑类似 的做法,只记录重链信息,即先递归算轻链,最后算重链,并保留重链信息,这样由于一个点到根的路径上只有 条轻边,所以空间复杂度降到 ,时间仍然是

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
//2021.10.25 by ljz
//email 573902690@qq.com
//if you find any bug in my code
//please tell me
const int N=4e4+10;
namespace MAIN{
int n;
char str[10];
int fa[N],cnt,sxor[N];
Pair a[N];
vector<int> G[N];
int id[N];
LL ans[N];
LL f[14][16384],g[16384];
int sz[N],son[N];
void dfs_sz(res x){
sz[x]=1;
for(auto tox:G[x]){
dfs_sz(tox),sz[x]+=sz[tox];
if(!son[x]||sz[son[x]]<sz[tox])son[x]=tox;
}
}
void dfs(res x,res dep){
ans[x]=f[dep][sxor[x]];
if(!son[x])return;
for(auto tox:G[x]){
if(tox==son[x])continue;
for(res S=0;S<16384;S++)f[dep+1][S]=min(f[dep][S],f[dep][S^a[tox].fi]+a[tox].se);
dfs(tox,dep+1);
}
for(res S=0;S<16384;S++)g[S]=min(f[dep][S],f[dep][S^a[son[x]].fi]+a[son[x]].se);
for(res S=0;S<16384;S++)f[dep][S]=g[S];
dfs(son[x],dep);
}
inline void MAIN(){
n=read();
res now=0;
for(res i=1;i<=n;i++){
scanf("%s",str+1);
if(str[1]=='A'){
res x=read(),y=read();
a[++cnt]=mp(x,y),fa[cnt]=now,sxor[cnt]=sxor[now]^x,G[now].pb(cnt),id[i]=(now=cnt);
}
else id[i]=(now=fa[now]);
}
for(res i=1;i<16384;i++)f[0][i]=INF;
dfs_sz(0),dfs(0,0);
for(res i=1;i<=n;i++)printf("%lld\n",ans[id[i]]);
}
}

[J Jewel Grab]

solution

题面:长度为 的序列,每个位置有颜色和权值,带修单点颜色,每次询问一个起点 ,每碰到一个之前出现过的颜色则 ,当 要小于 时停止,问每种颜色的最大权值的和。

做法:考虑维护 表示上一个或下一个是 位置颜色的位置,发现可以转成类似二维数点的东西,又因 比较小,所以每次暴力跳,然后对每种重复出现的颜色把权值全记下来,取个 即可,时间复杂度

[K Candy Ads]

solution

题面:

做法:

[L Random Permutation]

solution

题面:随机生成一个长度为 的序列 ,值域是 ,现要求你计算对于排列 ,满足 的期望。

做法:一眼全部独立,直接推出式子,好像是 ,注意到输出的 spj 是绝对误差,所以大胆输出就对了。