Search for a command to run...
Progressive hints first, then the full explanation and implementation when you're ready to cash out.
Review status
AI-generated and still unreviewed. Double-check the details before internalizing them.
Hints
Open only as much as you need to keep the solve alive.
Forget the edges for a second and look only at the degree multiset. Since the total degree sum is , the graph is beautiful exactly when no subset of vertices has degree sum .
Isolated vertices are free. You can build the real graph on fewer vertices, then leave the rest with degree ; subset sums do not change.
For an odd number of active vertices, try to make every degree either or , where . Cyclic graphs are perfect for this: on odd , adding all edges of cyclic distances gives a simple -regular graph.
Choose the active odd so that . Then is large, so any subset with more vertices has strictly larger degree sum than its complement. Equality basically dies by size imbalance.
When is even and is very dense, flip the problem: construct the missing edges as a beautiful graph on vertices, then output the complement inside . Because the missing-edge count is , any equal split in the complement would force an equal split in the missing graph.
Research note: I checked the Codeforces statement and the official tutorial page. The tutorial text is currently blank in the HTML, but the visible accepted construction uses the same skeleton: balanced cyclic graphs on odd active vertex counts, plus a complement trick for dense even cases. The statement above is still the canonical source.
Let
.
The total degree sum is , so the vertices can be split into two equal-degree-sum parts iff there exists some subset with . So our job is to construct a simple graph whose degree multiset has no subset sum .
A few tiny edge counts are impossible. The exceptional values are
For these, every simple graph with edges has some subset of vertices with degree sum . This is a small finite lemma: after deleting isolated vertices there are at most relevant vertices, and checking the graphical degree partitions of gives a subset sum every time. This is not the clever part; it is just the annoying pocket tax.
There is a companion dense-version exception. If is even and the number of missing edges from is in
then no answer exists. For a missing graph with that many edges, the same finite check, padded with isolated vertices, gives a subset of exactly vertices whose degree sum inside is the number of missing edges. In the complement graph, that subset has exactly half the total degree sum.
Now for the construction.
First, isolated vertices are harmless. If we can build a beautiful graph on vertices with edges, we just leave the other vertices isolated.
Assume the active vertex count is odd. We reduce by while
After this reduction,
Write
We want degrees
The parity works automatically because is odd, so and have the same parity.
If is even, add all cyclic edges of distances
This gives a -regular graph. Then add more edges of cyclic distance . These edges are new and distinct, and they increase exactly degrees by .
If is odd, start from the cyclic graph of degree , built using distances
Then skip/delete disjoint distance- edges. This lowers exactly vertices by , leaving the same desired degree multiset.
The edge count is exactly
Why is this degree sequence indivisible? Suppose a subset has vertices and contains of the high-degree vertices. Its degree sum is
For , the reduction above implies . Since is odd, one side of any partition has more vertices. Even if every vertex on the larger side has degree and every vertex on the smaller side has degree , the larger side still has larger degree sum:
So equality is impossible.
The boundary cases with small are where this clean inequality can become tight. The only dangerous reachable values are and . We already declared impossible. For , we use a special graph on vertices : take every edge touching at least one of . Its degrees are
A subset sum of would require
which has no solution. So is safely constructible.
Now suppose is even.
If
we recursively build the graph on vertices and leave vertex isolated.
Otherwise the graph is dense. Let
be the number of missing edges. Here . If , the dense exception says no solution exists.
Otherwise, recursively build a beautiful graph with edges on vertices . Then output
Why does complementing work? For a subset , let be the sum of degrees inside the missing graph over vertices of ; vertex has degree in . In the complement graph ,
If , then
But , so
The right side is a multiple of , so it must be . Therefore and . But is exactly a forbidden half-degree subset in . Contradiction.
Thus the complement graph is beautiful.
The construction outputs exactly edges. Its running time is per test because of sorting the missing-edge list in the complement step, and the total constraints easily fit. Memory usage is .
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
ll choose2(ll x) {
return x * (x - 1) / 2;
}
vector<pair<int, int>> special12() {
vector<pair<int, int>> e;
for (int a = 1; a <= 6; a++) {
for (int b = a + 1; b <= 6; b++) {
if (max(a, b) >= 4) e.push_back({a, b});
}
}
return e;
}
vector<pair<int, int>> build(int n, ll m) {
if (m == 1 || m == 2 || m == 4 || m == 6) return {};
if (m == 12) return special12();
if (n & 1) {
while (m <= choose2(n - 2)) n -= 2;
vector<pair<int, int>> e;
e.reserve((size_t)m);
ll q = 2 * m / n;
ll r = 2 * m % n;
if (q % 2 == 0) {
for (int v = 0; v < n; v++) {
for (int p = 0; p < q / 2; p++) {
int u = (v + 1 + p) % n;
e.push_back({v + 1, u + 1});
}
}
for (int v = 0; v < r / 2; v++) {
int u = (v + n / 2) % n;
e.push_back({v + 1, u + 1});
}
} else {
int skip = (n - (int)r) / 2;
for (int v = 0; v < n; v++) {
for (int p = 0; p < (q + 1) / 2; p++) {
if (v % 2 == 0 && p == 0 && skip > 0) {
--skip;
continue;
}
int u = (v + 1 + p) % n;
e.push_back({v + 1, u + 1});
}
}
}
return e;
}
ll missing = choose2(n) - m;
if (missing == 0 || missing == 1 || missing == 2 || missing == 4 || missing == 6) return {};
if (m <= choose2(n - 1)) {
return build(n - 1, m);
}
auto bad = build(n - 1, missing);
vector<pair<int, int>> miss;
miss.reserve(bad.size());
for (auto [a, b] : bad) {
if (a > b) swap(a, b);
miss.push_back({a, b});
}
sort(miss.begin(), miss.end());
vector<pair<int, int>> e;
e.reserve((size_t)m);
int ptr = 0;
for (int a = 1; a <= n; a++) {
for (int b = a + 1; b <= n; b++) {
if (ptr < (int)miss.size() && miss[ptr] == make_pair(a, b)) {
++ptr;
} else {
e.push_back({a, b});
}
}
}
return e;
}
int main() {
setIO();
int T;
cin >> T;
while (T--) {
int n;
ll m;
cin >> n >> m;
auto edges = build(n, m);
if (edges.empty()) {
cout << "No\n";
} else {
cout << "Yes\n";
for (auto [a, b] : edges) {
cout << a << ' ' << b << "\n";
}
}
}
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
ll choose2(ll x) {
return x * (x - 1) / 2;
}
vector<pair<int, int>> special12() {
vector<pair<int, int>> e;
for (int a = 1; a <= 6; a++) {
for (int b = a + 1; b <= 6; b++) {
if (max(a, b) >= 4) e.push_back({a, b});
}
}
return e;
}
vector<pair<int, int>> build(int n, ll m) {
if (m == 1 || m == 2 || m == 4 || m == 6) return {};
if (m == 12) return special12();
if (n & 1) {
while (m <= choose2(n - 2)) n -= 2;
vector<pair<int, int>> e;
e.reserve((size_t)m);
ll q = 2 * m / n;
ll r = 2 * m % n;
if (q % 2 == 0) {
for (int v = 0; v < n; v++) {
for (int p = 0; p < q / 2; p++) {
int u = (v + 1 + p) % n;
e.push_back({v + 1, u + 1});
}
}
for (int v = 0; v < r / 2; v++) {
int u = (v + n / 2) % n;
e.push_back({v + 1, u + 1});
}
} else {
int skip = (n - (int)r) / 2;
for (int v = 0; v < n; v++) {
for (int p = 0; p < (q + 1) / 2; p++) {
if (v % 2 == 0 && p == 0 && skip > 0) {
--skip;
continue;
}
int u = (v + 1 + p) % n;
e.push_back({v + 1, u + 1});
}
}
}
return e;
}
ll missing = choose2(n) - m;
if (missing == 0 || missing == 1 || missing == 2 || missing == 4 || missing == 6) return {};
if (m <= choose2(n - 1)) {
return build(n - 1, m);
}
auto bad = build(n - 1, missing);
vector<pair<int, int>> miss;
miss.reserve(bad.size());
for (auto [a, b] : bad) {
if (a > b) swap(a, b);
miss.push_back({a, b});
}
sort(miss.begin(), miss.end());
vector<pair<int, int>> e;
e.reserve((size_t)m);
int ptr = 0;
for (int a = 1; a <= n; a++) {
for (int b = a + 1; b <= n; b++) {
if (ptr < (int)miss.size() && miss[ptr] == make_pair(a, b)) {
++ptr;
} else {
e.push_back({a, b});
}
}
}
return e;
}
int main() {
setIO();
int T;
cin >> T;
while (T--) {
int n;
ll m;
cin >> n >> m;
auto edges = build(n, m);
if (edges.empty()) {
cout << "No\n";
} else {
cout << "Yes\n";
for (auto [a, b] : edges) {
cout << a << ' ' << b << "\n";
}
}
}
}