Ah, how I long to embrace
艰难的构造过程。
问题转化
先考虑怎么判定合法性。假设我们选定了两个集合 \(A,B\),我们是很难快速计算出度数和的。考虑怎么加速度数和的计算,发现题目只需要我们判断是否相等,因此不妨转化成大小关系,则两边同时 \(-1\) 显然并不会影响答案。那什么时候两个会同时 \(-1\) 呢?肯定是断了两个集合之间的边了。换个说法,也就是我们开始选定了点集,那么我们要进行断边分成两块,则断边是不影响集合的大小关系的。
也就是说,我们只需要判定在原图中的 \(deg\) 和是否相等就行了。而原图的 \(\sum deg=2m\),因此图合法当且仅当不存在一种度数的选择使得 \(\sum deg = m\)。
发现依然没有突破口。不妨先考虑什么时候一定是合法的,注意到 \(n\) 个点的环(其中 \(n\) 为奇数)一定是合法的。观察样例1,我们发现在这个环上连边也有机会是合法的。
构造
考虑进行结论的猜测,我猜的是 \((1,3)(2,4)(3,5)\) 这样的连法,但是发现这样子连到 \(n=7\) 的时候就开始不合法了!不太好。考察 \(n=7\),我们发现这样子连,只有到了度数变成了 \((3,3,3,3,3,3,4)\) 这样了,才开始又合法了。但是经过手玩,我们发现还有一种度数的方式是 \((3,3,3,3,3,3,2)\)。
于是换种猜测方式,考虑每一次选择度数最小的两个点进行连边,发现这样子的构造似乎很有道理。但是我们很容易发现这样子的建边并不容易,那么这是不是意味着我们的做法并没有正确性了呢?并不是的。不难发现在我们贪心的时候,节点的度数的差至多为 \(1\),而且显然这个是正确的,那么我们的节点的度数最后应该是形如 \((q,q,q,q,q+1,q+1,q+1)\) 这样的。那么我们不妨假设 \(q,r\),其中 \(r\) 表示的是 \(q+1\) 的节点的点的数量。不难发现的是,\(q,r\) 是同奇偶性的,证明显然。于是进行分讨。
q,r 同为偶数
考虑直接往后连,感觉不太行,于是考虑对称的连发,这样子就是往后连 \(q/2\) 条边,顺着连就行了。\(r\) 的解决方式也是同理的。
q,r 同为奇数
考虑按偶数的连,然后断边,具体的,我们可以直接断 \((1,2)(3,4)\) 这样的。然后也是可以构造的。
特殊情况
不难发现我们需要面对如果 \(n\) 为偶数然后 \(q\) 还刚好把我卡了怎么办?也就是 \(q\) 太大,导致我们不好构造了。
我们不得不对着 \(n\) 进行构造了。我曾尝试猜想过美丽图的反图也是美丽的。但是发现这个是假的,因为我们需要考虑点的度数变成了 \(n - deg\),因此做差也就是 \(n \cdot (|A| - |B|) - \sum_{v \in A} deg_v + \sum_{v \in B} deg_v\)。有了 \(n\) 的干扰,使得不好解决了。
可是现在呢,我们发现 \(m > (n - 1) \cdot (n - 2) / 2\)。假设我们的 \(A\) 只取 \(n/2-1\) 个点,则我们发现这个是一定 \(<m\) 的,不善!也就是说,\(A,B\) 要均分 \(n\)。也就是说我们上面的猜想在这一刻成立了!因此直接对着反图做一次就行了。然后就能得到完美图了。
证明
这个我不太会。我们考虑把 \(n\) 卡到最小的奇数,满足 \(n \cdot (n-1) \ge m\)。则 \(2m = qn + r\)。
假设存在 \(A\) 满足 \(deg\) 的和为 \(m\),设有 \(a\) 个点的度数为 \(q\),\(b\) 个点的度数为 \(q+1\)。
假设 \(q > r\),则有 \(aq + bq + b = m\),也就是 \(q(2a+2b)+2b=qn+r\)。变形,有 \(q(2a+2b-n)=r-2b\)。因为左边要么是 \(0\),要么是 \(q\) 的若干倍,因此只能是 \(0\),而我们也就要求右边是 \(0\) 了。也就是 \(b = r / 2\)。因此 \(r\) 要是偶数,但是 \(r\) 是偶数右边的奇偶性是奇的,不成立。
假设 \(q<r\)。则有 \(q(n-2a-2b) = 2b-r\)。两边同时加上 \((n-2a-2b)\),有 \((q+1)(n-2a-2b)=n-2a-r\)。考虑 \(n-2a-2b>1\),也就是 \((q+1) \le (q+1)(n-2a-2b)\)。也就是 \(q+1 \le n - 2a - r\)。等价于 \(q + r \le n - 2a - 1\)。也就是 \(q+r < n\)。所以我们只要 \(q + r \ge n\) 就行了。而根据检验,除了小部分情况,都可以得到这样的 \(q,r\)。根据打表,发现在 \(m={0,1,2,4,6,12}\)。我们得不到这样的 \(q\) 和 \(r\)。而 \(12\) 的构造,出题人做了一回人给出了,所以可以直接用。
Code
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false);cin.tie(0),cout.tie(0)
#define File(s) freopen(s".in","r",stdin);freopen(s".out","w",stdout)
#define LL long long
#define fi first
#define se second
int find(int n,int m){
int res = n;
if(res % 2 == 0) res ++ ;
while(res * (res - 1) / 2 < m) res += 2;
while(res >= 3 && (res - 2) * (res - 3) / 2 >= m) res -= 2;
return res;
}
vector< pair<int,int> > Make(int n,int m){
int q = 2 * m / n;
int r = 2 * m - n * q;
vector<pair<int,int> > res;
if(q % 2 == 0){
int dist = q / 2;
for(int i=1;i<=n;i++){
for(int j=1;j<=dist;j++){
int to = i + j;
if(to > n) to -= n;
res.push_back({min(to,i),max(to,i)});
}
}
dist = q / 2 + 1;
for(int i=1;i<=r/2;i++){
int to = i + dist;
if(to > n) to -= n;
res.push_back({min(to,i),max(to,i)});
}
}
else{
int dist = (q + 1) / 2;
r = n - r;
for(int i=1;i<=n;i++){
for(int j=1;j<=dist;j++){
int to = i + j;
if(i % 2 == 1 && j == 1 && r){r -= 2; continue;}
if(to > n) to -= n;
res.push_back({min(to,i),max(to,i)});
}
}
}
return res;
}
void solve(){
int n,m;
cin >> n >> m;
if(m == 1 || m == 2 || m == 4 || m == 6){
cout << "No\n";
return ;
}
else if(m == 12){
if(n < 6){
cout << "No\n";
return ;
}
cout << "Yes\n";
cout << "1 4\n1 5\n1 6\n2 4\n2 5\n2 6\n3 4\n3 5\n3 6\n4 5\n4 6\n5 6\n";
return ;
}
if(n * (n - 1) / 2 < m){
cout << "No\n";
return ;
}
int N = find(sqrt(m),m);
if(N <= n){
vector< pair<int,int> > ans = Make(N,m);
cout << "Yes\n";
for(pair<int,int> e : ans)
cout << e.fi << " " << e.se << "\n";
return ;
}
else{
int M = (n * (n - 1)) / 2 - m;
if(M == 0 || M == 1 || M == 2 || M == 4 || M == 6){
cout << "No\n";
return ;
}
vector< pair<int,int> > ans;
ans.clear();
cout << "Yes\n";
if(M == 12){
ans.push_back({1,4});ans.push_back({1,5});ans.push_back({1,6});
ans.push_back({2,4});ans.push_back({2,5});ans.push_back({2,6});
ans.push_back({3,4});ans.push_back({3,5});ans.push_back({3,6});
ans.push_back({4,5});ans.push_back({4,6});ans.push_back({5,6});
}
else{
int NN = find(sqrt(M),M);
ans = Make(NN,M);
}
set<pair<int,int> > st;
st.clear();
for(pair<int,int> e : ans)
st.insert(e);
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
if(st.count({i,j})) continue;
cout << i << " " << j << "\n";
}
}
}
}
int main(){
IOS;
int T;
cin >> T;
while(T -- )
solve();
return 0;
}

浙公网安备 33010602011771号