P10441 [JOISC 2024] 乒乓球 题解

Description

构造一个点数为 nn 的竞赛图,满足其中三元环的个数为 mm

n5000n\leq 5000

Solution

首先竞赛图的三元环个数是可以根据每个点的入度/出度求的。具体地,设 degideg_i 表示 ii 的出度,则三元环个数为 (n3)(degi2)\binom{n}{3}-\sum{\binom{deg_i}{2}}

考虑怎么判断有无解。

注意到如果 degi+1<degjdeg_i+1<deg_j,那么让 degidegi+1,degjdegj1deg_i\leftarrow deg_i+1,deg_j\leftarrow deg_j-1 一定能让三元环数最多,所以度数越均匀,三元环数就越多。所以三元环最多的情况下 degideg_i 一定等于 n2\lfloor\frac{n}{2}\rfloor 或者 n2\lceil\frac{n}{2}\rceil,于是就能求出最多的三元环数了。

fnf_n 表示 nn 个点的图三元环数量的最大值,结论是如果 m>fnm>f_n 则无解,否则有解。

构造就考虑先把初始度数设为数量最大时的情况,然后每次选择 degi=degjdeg_i=deg_j,让 degidegi1,degjdegj+1deg_i\leftarrow deg_i-1,deg_j\leftarrow deg_j+1,会让三元环数减一。如果选不出来,就说明 deg={0,1,2,,n1}deg=\{0,1,2,\ldots,n-1\},此时三元环数为 00,不需要再调整了。

由于每次操作可以看成选两个度数相等的点,将它们之间的边取反,并且初始状态一定能构造,所以最终也可以构造出来。

现在得到了每个点的度数,构造竞赛图就考虑每次选择度数最小的点 ii,向其余任意 degideg_i 个点连从 ii 出发的边,剩下的 n1degin-1-deg_i 个点就连到达 ii 的边,然后把 ii 删掉即可。

但是 mm 可能到 O(n3)O(n^3) 级别,暴力调整度数会超时。注意到 f(n)f(n1)f(n)-f(n-1)O(n2)O(n^2) 级别,所以只需要选择最小的 kk 满足 f(k)mf(k)\geq m,然后构造大小为 kk 三元环数为 mm 的图,然后对剩余的点连出一个有向无环图即可。

时间复杂度:O(n2logn)O(n^2\log n)

Code

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#include <bits/stdc++.h>

#define int int64_t

const int kMaxN = 5e3 + 5;

int n, m;
bool g[kMaxN][kMaxN];

int C(int n) { return 1ll * n * (n - 1) / 2; }

int calc(int n) {
if (n % 2 == 1) return 1ll * n * (n - 1) * (n - 2) / 6 - 1ll * n * C((n - 1) / 2);
else {
int k = (n - 1) / 2, cnt2 = C(n) - k * n, cnt1 = n - cnt2;
return 1ll * n * (n - 1) * (n - 2) / 6 - (1ll * cnt1 * C(k) + 1ll * cnt2 * C(k + 1));
}
}

void construct(int n, int m) {
static int cnt[kMaxN] = {0}, deg[kMaxN];
std::fill_n(cnt, n - 1, 0);
if (n % 2 == 1) {
cnt[(n - 1) / 2] = n;
} else {
int k = (n - 1) / 2, cnt2 = C(n) - k * n, cnt1 = n - cnt2;
cnt[k] = cnt1, cnt[k + 1] = cnt2;
}
std::priority_queue<int> q;
for (int i = 1; i < n - 1; ++i)
if (cnt[i] >= 2)
q.emplace(i);
for (int i = 1; i <= m; ++i) {
int x = q.top(); q.pop();
cnt[x] -= 2, ++cnt[x - 1], ++cnt[x + 1];
if (cnt[x] >= 2) q.emplace(x);
if (cnt[x - 1] == 2 && x - 1 >= 1) q.emplace(x - 1);
if (cnt[x + 1] == 2 && x + 1 < n - 1) q.emplace(x + 1);
}
int c = 0;
static int tmp[kMaxN];
for (int i = 0; i < n; ++i) {
for (int j = 1; j <= cnt[i]; ++j)
deg[++c] = i, tmp[c] = i;
}
// std::cerr << n << ' ' << m << " : ";
// for (int i = 1; i <= n; ++i) std::cerr << deg[i] << " \n"[i == n];
for (int i = 1; i <= n; ++i) {
std::vector<int> vec;
assert(i + deg[i] <= n);
// std::cerr << i << ' ' << deg[i] << '\n';
for (int j = i + 1; j <= n; ++j) vec.emplace_back(j);
std::sort(vec.begin(), vec.end(), [&] (int x, int y) { return deg[x] < deg[y]; });
for (int j = 0; j < vec.size(); ++j) {
int x = vec[j];
if (j < deg[i]) g[i][x] = 1;
else g[x][i] = 1, --deg[x];
}
}
// for (int i = 1; i <= n; ++i) {
// assert(std::count(g[i] + 1, g[i] + 1 + n, 1) == tmp[i]);
// }
}

void dickdreamer() {
std::cin >> n >> m;
if (calc(n) < m) return void(std::cout << "No\n");
for (int i = 1; i <= n; ++i)
std::fill_n(g[i] + 1, n, 0);
for (int k = 0; k <= n; ++k) {
if (calc(k) >= m) {
construct(k, calc(k) - m);
for (int i = 1; i <= n; ++i)
for (int j = std::max(i + 1, k + 1); j <= n; ++j)
g[i][j] = 1;
break;
}
}
std::cout << "Yes\n";
// int sum = 1ll * n * (n - 1) * (n - 2) / 6;
// for (int i = 1; i <= n; ++i) sum -= C(std::count(g[i] + 1, g[i] + 1 + n, 1));
// std::cerr << sum << '\n';
// for (int i = 1; i <= n; ++i, std::cerr << '\n')
// for (int j = 1; j <= n; ++j)
// std::cerr << g[i][j];
for (int i = 2; i <= n; ++i) {
for (int j = 1; j < i; ++j)
std::cout << g[i][j];
std::cout << '\n';
}
}

int32_t main() {
#ifdef ORZXKR
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);
int T = 1;
std::cin >> T;
while (T--) dickdreamer();
// std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";
return 0;
}

P10441 [JOISC 2024] 乒乓球 题解
https://sobaliuziao.github.io/2025/02/09/post/b2f45817.html
作者
Egg_laying_master
发布于
2025年2月9日
许可协议