0%

题目大意

Inc, Dec, Xor

有一个长度为 NN 的整数序列 A=(A1,A2,,AN)A=(A_1,A_2,\ldots,A_N)初始时 AA 的所有元素均为 00

给定 QQ 个操作,请按顺序依次处理。操作共有两种,格式如下:

  • 1 x:将 AxA_x 的值增加 11

  • 2:对每个 i=1,2,,Ni=1,2,\ldots,N,若 Ai1A_i \geq 1,则将 AiA_i 的值减少 11

请求出每次操作处理完毕后 A1,A2,,ANA_1,A_2,\ldots,A_N 的按位异或值。

关于按位异或
非负整数 A,BA,B 的按位异或 ABA \oplus B 定义如下:ABA \oplus B 在二进制表示下 2k2^kk0k \geq 0)位上的数字,当 A,BA,B 在二进制表示下 2k2^k 位上的数字恰有一个为 11 时为 11,否则为 00
例如 35=63 \oplus 5 = 6(二进制表示为 011101=110011 \oplus 101 = 110)。
一般地,kk 个非负整数 p1,p2,,pkp_1,p_2,\ldots,p_k 的按位异或定义为 (((p1p2)p3)pk)(\dots((p_1 \oplus p_2) \oplus p_3) \oplus \dots \oplus p_k),可以证明其结果与 p1,p2,,pkp_1,p_2,\ldots,p_k 的顺序无关。

输入从标准输入按以下格式给出:

1
2
3
4
5
N Q
query_1
query_2

query_Q

其中每个操作为以下两种格式之一:

1
1 x
1
2

输出 QQ 行。

ii 行(1iQ1\le i\le Q)输出第 ii 个操作处理完毕后 A1,A2,,ANA_1,A_2,\ldots,A_N 的按位异或值。

  • 1N5×1051\le N\le 5\times 10^5

  • 1Q5×1051\le Q\le 5\times 10^5

  • 1xN1\le x\le N

  • 输入的所有值均为整数

1
2
3
4
5
6
2 5
1 2
1 2
1 1
2
2
1
2
3
4
5
1
2
3
1
0

处理第 11 个操作后 A=(0,1)A=(0,1)0,10,1 的按位异或为 11,故第 11 行输出 11

处理第 22 个操作后 A=(0,2)A=(0,2)0,20,2 的按位异或为 22,故第 22 行输出 22

处理第 33 个操作后 A=(1,2)A=(1,2)1,21,2 的按位异或为 33,故第 33 行输出 33

处理第 44 个操作后 A=(0,1)A=(0,1)0,10,1 的按位异或为 11,故第 44 行输出 11

处理第 55 个操作后 A=(0,0)A=(0,0)0,00,0 的按位异或为 00,故第 55 行输出 00

1
2
3
4
5
6
7
8
9
3 8
1 2
1 3
1 1
1 2
1 1
2
1 3
1 1
1
2
3
4
5
6
7
8
1
0
1
2
1
0
1
2

思路讲解

那么这道题目的关键点就是这个,初始时 AA 的所有元素均为 00,以及我们只能增加一个元素啊,我们只要实时维护一个这个正数的这个集合遇到操作二暴力遍历就可以解决了。

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
int main() {
int n = readInt(), q = readInt();

/* alive:保存所有满足 A[i] >= 1 的下标,且保证【互不重复】。
* 维护方式:
* - A[x] 由 0 变 1 时 push_back(x)(这是唯一的“从零变非零”时机)
* - A[i] 由 1 变 0 时把它从 alive 中删除
* 因为 A[i] = 0 对异或没有贡献,所以只关心非零元素即可。
*/
vector<int> alive;
alive.reserve(min(n, q)); // 非零元素个数不会超过 min(N, 操作1次数)

int cur = 0; // cur = A[1] ^ A[2] ^ ... ^ A[n],实时维护

while (q--) {
int op = readInt();

if (op == 1) {
/* -------- 操作 1:A[x] += 1 -------- */
int x = readInt();

if (A[x] == 0) alive.push_back(x); // 从 0 变成非零,加入集合(不会重复)

cur ^= A[x]; // 先把旧值的贡献异或掉(旧值为 0 时是空操作)
++A[x];
cur ^= A[x]; // 再把新值的贡献异或上去
} else {
/* -------- 操作 2:所有非零元素 -1 --------
* 直接遍历 alive 暴力做。单次代价 = |alive|,
* 而这次操作让 sum(A) 恰好减少 |alive|,
* 由于 sum(A) 的总增量 <= 操作 1 的次数 <= Q,
* 所以所有操作 2 的总代价 <= Q,均摊 O(1)。
*/
int m = 0; // m 是“原地压缩”后新数组的长度
for (int idx : alive) {
cur ^= A[idx]; // 去掉旧值贡献
--A[idx];
cur ^= A[idx]; // 加上新值贡献(变成 0 时异或 0,无影响)

if (A[idx] > 0) alive[m++] = idx; // 仍非零则保留;归零的自然被覆盖删除
}
alive.resize(m); // 截断,完成删除
}

IO::writeInt(cur); // 每次操作后输出当前全局异或值
}

IO::flushOut();
return 0;
}

AC代码

https://atcoder.jp/contests/abc470/submissions/78274919

心路历程(WA,TLE,MLE……)

题目大意

题目描述

给定正整数 NN(1,2,,N)(1,2,\ldots,N) 的一个排列 P=(P1,P2,,PN)P=(P_1,P_2,\ldots,P_N)

有三个变量 x,y,cx,y,c,初始时 x=y=c=0x=y=c=0

你需要按 k=1,2,,Nk=1,2,\ldots,N 的顺序,依次执行下列两种操作之一:

  • 操作 11:若 x<Pkx < P_k,则将 cc 增加 11;随后将 xx 替换为 max(x,Pk)\max(x,P_k)

  • 操作 22:若 y<Pky < P_k,则将 cc 增加 11;随后将 yy 替换为 max(y,Pk)\max(y,P_k)

求最终 cc 的最大可能值。

输入格式

输入从标准输入以如下格式给出:

NN

P1 P2  PNP_1\ P_2\ \ldots\ P_N

输出格式

输出一行一个整数,表示答案。

数据范围

  • 1N5×1051\le N\le 5\times 10^5

  • PP(1,2,,N)(1,2,\ldots,N) 的一个排列

  • 输入的所有值均为整数

样例

1
2
5
4 3 1 2 5
1
4

按如下方式操作可以达到 c=4c=4

  • k=1k=1 时:执行操作 11,此时 (x,y,c)=(4,0,1)(x,y,c)=(4,0,1)

  • k=2k=2 时:执行操作 11,此时 (x,y,c)=(4,0,1)(x,y,c)=(4,0,1)

  • k=3k=3 时:执行操作 22,此时 (x,y,c)=(4,1,2)(x,y,c)=(4,1,2)

  • k=4k=4 时:执行操作 22,此时 (x,y,c)=(4,2,3)(x,y,c)=(4,2,3)

  • k=5k=5 时:执行操作 22,此时 (x,y,c)=(4,5,4)(x,y,c)=(4,5,4)

无论如何操作都无法使 cc 超过 44,因此输出 44

1
2
6
6 5 4 3 2 1
1
2
1
2
9
3 6 5 2 7 8 9 1 4
1
7

思路讲解

image

我们不难注意到,这个前缀最大值数组中出现的值,我们必须要选啊,而且不仅仅是必须要选,我们的有一个 X / Y 的上升序列一定就是长这个样!否则就不是很优秀啊。

AC代码

心路历程(WA,TLE,MLE……)

题目大意

题目描述

给定一个正整数 NN

你需要将集合 {0,1,2,,3N1}\{0,1,2,\ldots,3N-1\} 划分为 NN 个有序三元组 (x1,y1,z1),(x2,y2,z2),,(xN,yN,zN)(x_1,y_1,z_1),(x_2,y_2,z_2),\ldots,(x_N,y_N,z_N)

这些三元组必须同时满足以下所有条件:

  1. 集合 {0,1,2,,3N1}\{0,1,2,\ldots,3N-1\} 中的每个整数在所有三元组中恰好出现一次。等价地说,序列 x1,y1,z1,x2,y2,z2,,xN,yN,zNx_1,y_1,z_1,x_2,y_2,z_2,\ldots,x_N,y_N,z_N 必须是集合 {0,1,2,,3N1}\{0,1,2,\ldots,3N-1\} 的一个排列。

  2. 对于每个 i{1,2,,N}i \in \{1,2,\ldots,N\},都必须满足 zi>0z_i>0ximodzi=yix_i \bmod z_i = y_i

其中,amodba \bmod b 表示非负整数 aa 除以正整数 bb 所得的余数。

可以证明,在给定的数据范围内,对于任意 NN 至少存在一种合法的构造。你只需要输出任意一种合法的构造即可。

输入格式

输入仅包含一行一个正整数 NN1N2×1051 \le N \le 2\times 10^5)。

输出格式

输出 NN 行。

ii 行需要包含三个整数 xi,yi,zix_i, y_i, z_i,表示第 ii 个有序三元组。

对于每个 i{1,2,,N}i \in \{1,2,\ldots,N\},你的输出必须满足 0xi,yi,zi<3N0 \le x_i, y_i, z_i < 3Nzi>0z_i > 0ximodzi=yix_i \bmod z_i = y_i

此外,输出的序列 x1,y1,z1,x2,y2,z2,,xN,yN,zNx_1,y_1,z_1,x_2,y_2,z_2,\ldots,x_N,y_N,z_N 必须是集合 {0,1,2,,3N1}\{0,1,2,\ldots,3N-1\} 的一个排列。

如果存在多种合法的构造,输出任意一种即可。

样例

1
3
1
2
3
5 0 1
7 3 4
8 2 6

样例输出给出了三个有序三元组:(5,0,1)(5,0,1)(8,2,6)(8,2,6),以及 (7,3,4)(7,3,4)

它们分别满足等式:5mod1=05 \bmod 1 = 08mod6=28 \bmod 6 = 27mod4=37 \bmod 4 = 3

此外,这些三元组中出现的所有整数恰好为 0,1,2,3,4,5,6,7,80,1,2,3,4,5,6,7,8,这正是集合 {0,1,,3N1}\{0,1,\ldots,3N-1\} 中的所有整数。

思路讲解

AC代码

心路历程(WA,TLE,MLE……)

题目大意

括号凸包

给定二维平面上的 nn 个点,所有点互不相同,且不存在三点共线。每个点上写有一个括号,可能是左括号 (\texttt{(} ,也可能是右括号 )\texttt{)}

我们称一个字符串 SS 是一个合法括号序列,当且仅当它可以由如下递归规则生成:

  • 空串是一个合法括号序列;

  • 如果 AA 是合法括号序列,那么字符串 (A)\texttt{(}A\texttt{)} 也是合法括号序列;

  • 如果 AABB 都是合法括号序列,那么 ABAB 也是合法括号序列。

例如,()\texttt{()}(())\texttt{(())}()()\texttt{()()} 都是合法括号序列,而 )(\texttt{)(}(()\texttt{(()}())(\texttt{())(} 不是合法括号序列。

现在,你需要从给定的点中选出若干个互不相同的点作为顶点,构成一个凸多边形。在本题中,一个由 mm 个点 pa1,pa2,,pamp_{a_1},p_{a_2},\dots,p_{a_m} 构成的多边形被称为凸多边形,当且仅当满足:

  • m3m \ge 3

  • 这些点按照 a1,a2,,ama_1,a_2,\dots,a_m 的顺序依次连接,并连接 ama_ma1a_1 后,形成一个简单多边形(即多边形的边仅在相邻边的端点处相交,不相邻边互不相交);

  • 对于该多边形的每一条边,其余所有顶点都严格位于这条边所在直线的同一侧。

换句话说,所选出的点必须恰好按照它们在自身凸包上的环形顺序排列,并且所有内角都严格小于 180180^\circ,凸多边形上不存在三点共线。

对于一个凸多边形,任选其边界上的一个顶点作为起点,并沿着多边形边界按顺时针或逆时针方向依次遍历所有顶点,最后回到起点前停止。这样可以得到一个长度为 mm 的括号序列:若当前顶点上写有左括号,则写下 (\texttt{(};若当前顶点上写有右括号,则写下 )\texttt{)}

你的任务是找到包含至少一个左括号的凸多边形,使得对于该多边形上的任意一个写有左括号的顶点,以它作为起点沿多边形边界并以任意方向遍历得到的括号序列都是合法括号序列。请计算满足条件的凸多边形个数,并将结果对 998244353998244353 取模后输出。

第一行包含一个整数 TT1T1001 \le T \le 100),表示数据组数。

对于每组数据:

第一行包含一个整数 nn1n5001 \le n \le 500),表示点的数量。

接下来 nn 行,每行包含三个整数 xi,yi,tix_i, y_i, t_i0xi,yi1090 \le x_i, y_i \le 10^9ti{0,1}t_i \in \{0, 1\}),表示第 ii 个点的坐标和括号类型。其中 ti=0t_i = 0 表示左括号, ti=1t_i = 1 表示右括号。

保证每组数据中所有点互不相同,且不存在三点共线

保证所有数据的 nn 之和不超过 10001000

对于每组数据,输出一行一个整数,表示满足条件的凸多边形方案数对 998244353998244353 取模后的结果。

Plaintext

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
5
4
1 1 0
2 4 1
3 9 0
4 16 1
5
1 1 0
2 4 0
3 9 0
4 16 1
5 25 1
6
47 58 0
30 23 0
27 34 1
35 7 1
10 30 1
1 25 1
8
10 5 0
10 16 0
1 5 0
24 9 0
6 2 0
6 12 0
7 18 1
3 13 1
1
0 0 0

Plaintext

1
2
3
4
5
1
0
1
0
0
  • 对于第一组样例44 个点的坐标形如抛物线 y=x2y=x^2,因此这 44 个点的任意大小大于等于 33 的子集都能构成凸多边形。这四个点的括号类型依次为 (\texttt{(})\texttt{)}(\texttt{(})\texttt{)}。若选择全部 44 个点构成凸四边形,其顺时针与逆时针的环形括号序列循环节均为 ()()\texttt{()()}。无论从第 11 个点(左括号)还是第 33 个点(左括号)出发,按顺时针或逆时针方向生成的字符串均为 ()()\texttt{()()},是合法序列。可以证明,选取其他任何 33 个点构成的三角形均因括号数量为奇数而无法满足条件。因此,方案数为 11

  • 对于第二组样例:给出 55 个点,括号类型依次为 (\texttt{(}(\texttt{(}(\texttt{(})\texttt{)})\texttt{)}。经尝试,无法选出任何一个使得“从任意左括号出发、沿任意方向遍历”均产生合法序列的凸多边形。方案数为 00

  • 对于第五组样例:只有 11 个点,无法满足构成凸多边形要求的最少顶点数(m3m \ge 3),故方案数为 00

思路讲解

image

首先,题目中有关于括号凸包的表述啊,这个括号串肯定是形如这个 ()()()()...()()()()()()...()() 这样子的形式啊。

因为每个括号串的第一个字符肯定是这个 ,最后一个字符肯定是 ,所有奇数位置必是 ,这个是因为所有的奇数位置肯定是这个开头(题目中要求每个左括号位置循环移动到开头仍然是合法括号串)。

然后接着就是标题里面的结论啊:

判断一个凸包是否合法,只需要看这个向量的方位角是否可通过循环位移排成递增即可啊,当然前提是不能 3 点共线

image

那么这个结论实际上是这样子来的啊:

image

image

image

因为我们最终会绕一圈(起点和终点相同),因此我们其实是在判断,是否多绕了一圈

这个三点不能共线的规定是用在这个 dp 转移里面的。

dp 状态我们先这样子定义,但是这样子:

image

image

image

1
2
3
4
vector<vector<ll> > dp(N, vector<ll>(N));
for (int i = 0; i < N; ++i) {
dp[i][i] = 1;
}

这样子会多计算出来一些东西,最后减掉就行啊。

1
2
3
4
5
6
7
for (int i = 0; i < N; ++i) {
ans += dp[i][i];
ans %= mod;
}
// 减掉多余的东西啊
ans -= SZ(vec_ijs) / 2;
ans -= N;

具体转移的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
vector<VecIJ> vec_ijs;
vec_ijs.reserve(N * N);
for (int i = 0; i < SZ(A); ++i) {
for (int j = 0; j < SZ(A); ++j) {
if (i == j) continue;
if (A[i].c != A[j].c) {
auto diff = A[j].p - A[i].p;
vec_ijs.push_back({diff, i, j});
}
}
}
// 进行极角排序(上面重载过 VecIJ 的比较运算符号)
sort(all(vec_ijs));
// 按照边的方位角方向,进行这个转移
for (auto [_,u,v]: vec_ijs) {
for (int src = 0; src < N; ++src) {
dp[src][v] += dp[src][u];
dp[src][v] %= mod;
}
}

AC代码

AC
https://acm.hdu.edu.cn/contest/view-code?cid=1233&rid=11368

心路历程(WA,TLE,MLE……)

题目大意

这是一份为您整理好的整洁、规范的中文题面,去除了杂乱的内容且未包含任何解题思路:

题目描述:天下一武道会 (Tenkaichi Budōkai)

时间限制: C/C++/Rust/Pascal 1秒,其他语言2秒

空间限制: C/C++/Rust/Pascal 1024 MB,其他语言2048 MB

特殊判定 (Special Judge): 是,64位整数输入输出格式:%lld

天下一武道会汇聚了来自世界各地的 nn 名武术家。武术家们的编号为 1,2,,n1, 2, \ldots, n

在比赛开始前,两名官员分别提交了固定的优先级列表 PPQQ。每个列表都恰好包含每位武术家一次,尽管武术家在两个列表中的排列顺序可能不同。

初始时,列表为:

P=(p1,p2,,pn)P = (p_1, p_2, \ldots, p_n)

Q=(q1,q2,,qn)Q = (q_1, q_2, \ldots, q_n)

其中这两个序列都是 1,2,,n1, 2, \ldots, n 的排列。一旦提交,两个列表的顺序都不允许被重新排列。

比赛委员会使用以下规则来模拟比赛。只要至少还有两名武术家剩余,就可以进行一场比赛:

uuvv 分别为当前列表 PPQQ 中排在最前面的未被淘汰的武术家。

  • 如果 u=vu = v,说明两位官员提名了同一位武术家。由于武术家不能与自己对战,且任何一位官员都不能跳过他们列表中的第一位武术家,此时模拟过程将陷入停滞状态,无法继续进行后续比赛。

  • 否则(即 uvu \neq v),uuvv 将进行对决。在模拟中,可以从 {u,v}\{u, v\} 中任意选择一名武术家 zz 作为败者。武术家 zz 将被淘汰出局,他也会同时从 PPQQ 两个列表中被移除。移除后,每个列表中剩余武术家的相对顺序保持不变。

经过恰好 n1n-1 场成功的比赛后,最终将只剩下一名武术家。这名武术家将被宣布为天下一武道会的冠军。

现在,你支持武术家 xx。请判断:是否存在一种合法的比赛胜负序列,使得整个模拟过程永远不会陷入停滞状态,并且武术家 xx 最终成为冠军?

如果存在这样的序列,请输出任意一个符合条件的被淘汰武术家序列。

输入格式

第一行包含两个整数 nnxx2n2×1052 \le n \le 2\times 10^51xn1 \le x \le n),分别表示武术家的数量和你希望成为冠军的武术家编号。

第二行包含 nn 个整数 p1,p2,,pnp_1, p_2, \ldots, p_n。保证序列 PP1,2,,n1, 2, \ldots, n 的一个排列。

第三行包含 nn 个整数 q1,q2,,qnq_1, q_2, \ldots, q_n。保证序列 QQ1,2,,n1, 2, \ldots, n 的一个排列。

输出格式

如果在不陷入停滞状态的前提下,无法使武术家 xx 成为冠军,请输出一行 NO

否则,第一行输出 YES

第二行输出 n1n-1 个整数 z1,z2,,zn1z_1, z_2, \ldots, z_{n-1},其中 ziz_i 表示在第 ii 场比赛中被淘汰的武术家。

注意:

在进行第 ii 场比赛前,设 uiu_iviv_i 分别为 PPQQ 中剩余排在最前面的武术家。你的输出必须满足 uiviu_i \neq v_izi{ui,vi}z_i \in \{u_i, v_i\}。在执行完全部的 n1n-1 场淘汰操作后,剩余的唯一武术家必须是 xx

如果存在多个符合条件的淘汰序列,输出其中任意一个均视为正确。

样例

样例 1

输入:

Plaintext

1
2
3
3 3
2 3 1
3 1 2

输出:

Plaintext

1
NO

样例 2

输入:

Plaintext

1
2
3
3 1
2 1 3
3 2 1

输出:

Plaintext

1
2
YES
2 3

样例 3

输入:

Plaintext

1
2
3
5 1
2 4 3 1 5
4 3 5 2 1

输出:

Plaintext

1
2
YES
4 3 2 5

样例解释

下面是对 样例 3 输出的详细解释:

初始时,PPQQ 中剩余排在最前面的武术家分别是 2 和 4。他们进行对决,武术家 4 被淘汰。列表更新为:

P=(2,3,1,5)P = (2, 3, 1, 5)

Q=(3,5,2,1)Q = (3, 5, 2, 1)

下一场比赛在武术家 2 和 3 之间进行。武术家 3 被淘汰,列表更新为:

P=(2,1,5)P = (2, 1, 5)

接下来,被提名的武术家是 2 和 5。武术家 2 被淘汰,此时:

P=(1,5)P = (1, 5)

Q=(5,1)Q = (5, 1)

最后,武术家 1 和 5 面对面进行对决,武术家 5 被淘汰。两个列表现在都只剩下武术家 1。

因此,模拟过程从未陷入停滞,武术家 1 成功成为了天下一武道会的冠军。

思路讲解

不想要卡死=尽量晚卡死啊

image

image

那么维护这样子的一个距离啊,可以使用这个 pbds。

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

int choose_p_or_q() {
if (aliveP.empty() || aliveQ.empty()) {
return -1;
}
auto [pid,qid] = make_tuple(*aliveP.begin(), *aliveQ.begin());
ll pval = P[pid];
ll qval = Q[qid];
if (pval == qval) {
return -1;
}
ll disp = aliveQ.order_of_key(valToQPos[pval]);
ll disq = aliveP.order_of_key(valToPPos[qval]);
auto erase_q = [&]() {
++ans_idx;
Ans[ans_idx] = Q[qid];
aliveQ.erase(qid);
aliveP.erase(valToPPos[qval]);
};
auto erase_p = [&]() {
++ans_idx;
Ans[ans_idx] = P[pid];
aliveP.erase(pid);
aliveQ.erase(valToQPos[pval]);
};
if (pval == X) {
erase_q();
} else if (qval == X) {
erase_p();
} else if (disp >= disq) {
erase_q();
} else {
erase_p();
}
return 0;
}

不断反复调用 choose_p_or_q(),即可啊。

1
2
3
4
5
6
7
8
9
10
11
while (SZ(aliveP) >= 2 || SZ(aliveQ) >= 2) {
int res = choose_p_or_q();
if (res == -1) {
cout << "NO\n";
return;
}
}
cout << "YES\n";
for (int i = 1; i <= ans_idx; ++i) {
cout << Ans[i] << " ";
}

AC代码

AC
https://ac.nowcoder.com/acm/contest/view-submission?submissionId=84410045

心路历程(WA,TLE,MLE……)