0%

The 2025 ICPC 德国 German Collegiate Programming Contest——A. Around the Table

题目大意

题目名称:Around the Table

题意总结
公园里有一张乒乓球桌,初始时左边队列有 \ell 个人,右边队列有 rr 个人。左边队首的人先持球。
游戏规则如下:

  1. 持球者将球打到对面,然后立刻跑到对面队列的队尾。

  2. 对面队首的人接球后成为新的持球者,重复上述过程。
    假设游戏进行无限次(101010010^{10^{100}} 次击球),你需要计算总共会出现多少对不同的“对决组合”。
    注意:两个人面对面即为一次对决,A 对战 B 与 B 对战 A 被视为同一种组合,不重复计算。

输入格式
一行包含两个整数 \ellrr2109,1r1092 \le \ell \le 10^9, 1 \le r \le 10^9),分别表示初始时左侧和右侧的人数。

输出格式
输出一个整数,表示会出现的不同对决组合的数量。

样例 1 解释
输入:2 2
输出:6
假设左边初始为 A, B,右边初始为 D, E。
流程推演:

注意啊,题目实际上求的是面对面情况,就是面对面过的这个 pair 的数量。当然,这 Pair 是一个无序对

image

  1. A 对 D(记录组合 {A, D})。A 击球后去右边队尾。局面变更为:左 [B],右 [D, E, A]。

  2. B 对 D(记录组合 {B, D})。D 击球后去左边队尾。局面变更为:左 [B, D],右 [E, A]。

  3. B 对 E(记录组合 {B, E})。B 击球后去右边队尾。局面变更为:左 [D],右 [E, A, B]。

  4. D 对 E(记录组合 {D, E})。E 击球后去左边队尾。局面变更为:左 [D, E],右 [A, B]。

  5. D 对 A(组合 {A, D} 已存在)。D 击球后去右边队尾。局面变更为:左 [E],右 [A, B, D]。

  6. E 对 A(记录组合 {E, A})。A 击球后去左边队尾。局面变更为:左 [E, A],右 [B, D]。

  7. E 对 B(组合 {B, E} 已存在)。E 击球后去右边队尾。局面变更为:左 [A],右 [B, D, E]。

  8. A 对 B(记录组合 {A, B})。B 击球后去左边队尾。局面变更为:左 [A, B],右 [D, E]。
    此时回到初始局面(A 对 D),循环结束。
    总共出现的不重复组合为:{A, D}, {B, D}, {B, E}, {D, E}, {E, A}, {A, B},共 6 种。

思路讲解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
_______________[ Sample Testcase #1 INPUT ]_______________
2 2

_______________[ Sample Testcase #1 OUTPUT]_______________
6


[-] FAILURE: RUNTIME ERROR
2 3
1 3
1 4
3 4
3 2
4 2
4 1
2 1
2 3
1 3
1 4

我们还是把第一个数字给反转一下吧,把第一个数字反转一下更加符更加符合我们人类的这个直觉。

你会发现一二三四五,这样子是轮流出现的,是轮流出现的,就像模运算一样。

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
_______________[ Sample Testcase #1 INPUT ]_______________
2 2

_______________[ Sample Testcase #1 OUTPUT]_______________
6


[-] FAILURE: RUNTIME ERROR
1 3
2 3
2 4
3 4
3 1
4 1
4 2
1 2
1 3
2 3
2 4

_______________[ Sample Testcase #2 INPUT ]_______________
2 3

_______________[ Sample Testcase #2 OUTPUT]_______________
10


[-] FAILURE: RUNTIME ERROR
1 3
2 3
2 4
3 4
3 5
4 5
4 1
5 1
5 2
1 2
1 3
2 3
2 4
3 4
3 5
4 5
4 1
5 1
5 2
1 2
1 3

image

规律大概是这样的,不过还是不是特别清楚呢。我们使用零 base 的下标再注释一下。

image

这下子这个规律就非常清楚了。不过注意啊,其实就是第奇数个加 gap ,第偶数个加 gap-1,它不会加 gap 加二什么之类的。

image

那么奇数位,(i,(i+gap)modn)(i,(i+gap)\mod n),这个东西内部,有没有可能重复呢?不难写出:

ii+gapi+gapii\equiv i'+gap \\ i+gap\equiv i' \\

art
1
2
3
4
5
i      ≡ i' + gap  (mod n)    ①
i + gap ≡ i' (mod n) ②

① - ②: -gap ≡ gap (mod n)
即: 2 * gap ≡ 0 (mod n)

注意啊,处理这种同余式子可以加减乘但是不能除。如果除的话,必须确保逆元存在。逆元存在条件就是你要除的数字和和这个 mod n 的这个 n 是互质的。

注意啊,处理各种各样的式子,这个都是先要把这个变量给消掉,对吧?这个 i 和 i’ 都是变量,它们这个式子非常优美,可以直接消掉

我们接下来看,就是说i 加 gap 和 i 加 gap 减一这两个环是否会有相同的情况。

image

如上图所示,无非其实就是两种相同的情况嘛。

image

那么另外一种情况就是有可能成立的了。也就是二 gap 减一,和百分之 n,mod n 是零。

image

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void Solve() {
ll L,R;
cin >> L >> R;
ll N=L+R;
// 就是 L
ll gap1=(L+1)-1;
ll ans1=N;
// 如果是这个重复了,由于与这个 i 无关,因此所有 i 都有相同,总个数就是 N/2
if (2*gap1%N==0) {
ans1=N/2;
}
ll gap2=gap1-1;
ll ans2=N;
if (2*gap2%N==0) {
ans2=N/2;
}
// 相同情况处理
if ((gap1+gap2)%N==0) {
ans2=0;
}
cout<<ans1+ans2<<"\n";
}

AC代码

AC
https://qoj.ac/submission/2027025

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