0%

2026 杭电春季联赛 3——1006-骰子大战(一定要好好读题,把题面中的所有限制信息都读到)

题目大意

题目描述
需要构造 nn 个具有 kk 个面的骰子,每个面上的数字取值范围为 0m0 \sim m
两个骰子进行对决时,随机掷出一个面,点数大者获胜。要求构造的骰子组合必须同时满足以下三个条件:

  1. 循环劣势:形成 123n1n11 \to 2 \to 3 \to \dots \to n-1 \to n \to 1 的胜负关系。即 1 号骰子输给 2 号,2 号输给 3 号,……,nn 号输给 1 号(“输给”定义为在 k×kk \times k 种可能的掷出组合中,获胜的次数严格少于对方)。

  2. 绝对无平局每个数字至多只能出现在一个骰子上,保证任意两个骰子对决时不可能掷出相同的点数。

  3. 字典序最小:将 1 号到 nn 号骰子上的所有数字按顺序拼接成一个长度为 n×kn \times k 的序列,要求该序列在所有合法方案中字典序最小。

输入格式
第一行输入一个正整数 TT,表示测试数据组数。
接下来每组数据输入三个正整数 nnmmkk,分别表示骰子数量、面上的最大允许数字、每个骰子的面数。

输出格式
对于每组数据,输出一行 n×kn \times k 个用空格分隔的整数,依次表示 1 号到 nn 号骰子各个面上的数字。

样例数据

输入样例:

1
2
1
3 4 3

输出样例:

1
0 3 3 1 1 4 2 2 2

样例解释
输入代表需要构造 33 个骰子,每个骰子有 33 个面,数字范围在 040 \sim 4 之间。根据输出样例,三个骰子的构造如下:

  • 1 号骰子:[0, 3, 3]

  • 2 号骰子:[1, 1, 4]

  • 3 号骰子:[2, 2, 2]

胜负关系验证(总对决情况数为 3×3=93 \times 3 = 9 种):

  • 1 号 vs 2 号:1 号获胜的情况为 3>1(共 4 次),2 号获胜的情况为 1>01>04>04>34>3(共 5 次)。2 号胜率更高,1 号输给 2 号

  • 2 号 vs 3 号:2 号获胜的情况为 4>2(共 3 次),3 号获胜的情况为 2>1(共 6 次)。3 号胜率更高,2 号输给 3 号

  • 3 号 vs 1 号:3 号获胜的情况为 2>0(共 3 次),1 号获胜的情况为 3>2(共 6 次)。1 号胜率更高,3 号输给 1 号

该方案数字各不相同(无平局),构成了 12311 \to 2 \to 3 \to 1 的循环劣势,且可以证明拼接后的序列 0 3 3 1 1 4 2 2 2 是所有满足条件的方案中字典序最小的。

思路讲解

image

首先,我们为什么会想到双段构造?呃,其实正常的思维链路应该是,我们先想怎么构造,

其实题面里面讲的非常清楚,一个骰子最多只会有两种不同的数字,每个数字仅能出现在至多一个骰子上。

image

那都说了,最多两个数,那还能不是双段构造吗?

如果分成双段构造,那么不难看出:

早段1<早段2<<早段n\text{早段}_1 < \text{早段}_2 < \dots < \text{早段}_n,$\text{晚段}_1 < \text{晚段}_2 < \dots < \text{晚段}_n $(为了字典序最小,这两个条件是必须的),但是早晚段之间是什么关系呢?

注意啊,为了赢得游戏,早段n<晚段1\text{早段}_n < \text{晚段}_1,这个也是为了赢得游戏,满足所谓的“循环劣势要求”,所必须的这个构造,一个的最小的,大于一个的最大的,两者之间是绝对不会发生这个穿插的这个情况的,因此就是 早段1<早段2<<早段n<晚段1<晚段2<<晚段n\text{早段}_1 < \text{早段}_2 < \dots < \text{早段}_n < \text{晚段}_1 < \text{晚段}_2 < \dots < \text{晚段}_n

okay,那这道题目比较关键的部分就做完了,当然,还需要处理一些细节问题,就是每个段的早段是几个数,晚段是几个数?

不过贪心求解的部分也不是那么容易的。

首先,先写出一系列的这个获胜条件:

image

接着,我们要进行这个贪心求解,我们不难发现:

image

然后我们知道了 x1 的值,后面就用前面的限制,一个一个往后推就行了。

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
void gen_eraly_seg() {
for (int i = 1; i <= N; ++i) {
ll early_sz;
if (i == 1) {
early_sz = K - (bound_win + K - 1) / K;
} else {
if (early_sz_ls[i - 1] - K == 0) {
early_sz = K;
} else {
early_sz = (bound_win - K * K) / (early_sz_ls[i - 1] - K);
}
}
early_sz = min(early_sz, K);
early_sz_ls[i] = early_sz;
for (int j = 1; j <= early_sz; ++j) {
ans_mat[i][j] = idx;
}
if (early_sz != 0) {
++idx;
}
}
}

void gen_late_seg() {
for (int i = 1; i <= N; ++i) {
for (int j = early_sz_ls[i] + 1; j <= K; ++j) {
ans_mat[i][j] = idx;
}
if (early_sz_ls[i] != K) {
++idx;
}
}
}

AC代码

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

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

除零错误——INTEGER_DIVIDE_BY_ZERO