AGC035 Skolem XOR Tree

构造题.

当 $n=2^k$ 时,显然无解,因为那两个权值为 $n$ 的点路径上权值异或和一定会 $<n$ .

否则,若 $n$ 为奇数, $n$ 至少为 $3$ ,可以做如下构造:

即,将两组 $1,2,3$ 串在一起,从 $4$ 开始,将 $k,k+1$ 串在一起,分别正着,反着挂在中间那个 $1$ 下面.

容易验证这样做是合法的.

若 $n$ 为偶数,只需要先构造出 $n-1$ 的解,再将两个 $n$ 挂上去.

和中间那个 $1$ 直接相连的点中,包含了 $2\sim n-1$ 的所有权值.

当 $n​$ 不为 $2​$ 的幂的时候,总能在 $2\sim n-1 ​$ 中选出 $2​$ 个数 $x,y​$ ,使得 $x\oplus y\oplus 1=n​$ ,将这两个 $n​$ 挂在上面即可.

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
//%std
#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
typedef long long ll;
inline int read()
{
int out=0,fh=1;
char jp=getchar();
while ((jp>'9'||jp<'0')&&jp!='-')
jp=getchar();
if (jp=='-')
fh=-1,jp=getchar();
while (jp>='0'&&jp<='9')
out=out*10+jp-'0',jp=getchar();
return out*fh;
}
void report(int x,int y)
{
printf("%d %d\n",x,y);
}
int N;
void solve(int n)
{
report(1,2);
report(2,3);
report(3,1+N);
report(1+N,2+N);
report(2+N,3+N);
for(int i=4;i<=n;i+=2)
{
report(1+N,i+N);
report(i+N,i+1+N);
report(1+N,i+1);
report(i+1,i);
}
}
int main()
{
int n=read();
N=n;
if(__builtin_popcount(n)==1)
puts("No");
else
{
puts("Yes");
if(n&1)
solve(n);
else
{
solve(n-1);
for(int i=2;i<n;++i)
{
int j=(n+1)^i;
if(1<j && j<n && i!=j)
{
report(n,i&1?i:i+N);
report(n+N,j&1?j:j+N);
break;
}
}
}
}
return 0;
}