A. XOR Circle
题意:
给定
n
(
n
<
=
1
0
5
)
n(n<=10^5)
n(n<=105)个数字
a
[
1
]
a[1]
a[1]~
a
[
n
]
a[n]
a[n],询问是否能够将其重排成一个首位相接的环形数组,使得每个
a
[
i
]
(
1
<
=
i
<
=
n
)
a[i](1<=i<=n)
a[i](1<=i<=n)等于与其相邻的两个数字的异或和。
题解:
很显然重排后数组满足以下形式
a
[
i
]
a[i]
a[i] ^
a
[
i
+
1
]
a[i+1]
a[i+1] ^
a
[
i
+
2
]
a[i+2]
a[i+2] =
0
0
0
a
[
i
+
1
]
a[i+1]
a[i+1] ^
a
[
i
+
2
]
a[i+2]
a[i+2] ^
a
[
i
+
3
]
a[i+3]
a[i+3] =
0
0
0
所以
a
[
i
]
a[i]
a[i]等于
a
[
i
+
3
]
a[i+3]
a[i+3]
先讨论数组全零的情况,这个情况肯定有解;
对于剩下的情况,很显然,如果n不是3的倍数的话,必然无解。
那么我们分2类讨论:
当整个数组只有2种数字的时候,那么一定是
N
/
3
N/3
N/3个
0
0
0和
2
∗
N
/
3
2*N/3
2∗N/3个其他数字,否则一定不行。
当整个数字只有3种数字
x
,
y
,
z
x,y,z
x,y,z的时候,那么一定是这三种数字的数量相同,并且
x
x
x ^
y
y
y ^
z
z
z =
0
0
0,否则不行。
然后其他情况都不行。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,a[100004];
set<int>tr;
map<int,int>mert;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=n;i++){
tr.insert(a[i]);
}
if(tr.size()==1 && (*tr.begin())==0){
return puts("Yes"),0;
}
if(tr.size()==2){
if(n%3!=0)return puts("No"),0;
mert.clear();
int x=-1;
for(int i=1;i<=n;i++){
mert[a[i]]++;
if(a[i]!=0)x=a[i];
}
if(mert[0]==n/3&&mert[x]==n*2/3){
return puts("Yes"),0;
}
else return puts("No"),0;
}
if(tr.size()==3){
if(n%3!=0)return puts("No"),0;
mert.clear();
for(int i=1;i<=n;i++){
mert[a[i]]++;
}
int p=0;
for(int x:tr){
if(mert[x]!=n/3)return puts("No"),0;
p^=x;
}
if(p)return puts("No"),0;
else return puts("Yes"),0;
}
return puts("No"),0;
return 0;
}
B.Even Degrees
题意:
给定一个
n
n
n个点
m
m
m条边的无向图,要求给每条边重定向,使得每个点的出度都是偶数。
题解:
这是个很迷的构造方法…
首先
m
m
m如果是奇数,那么一定不行。
你先随便从一个点开始dfs,然后从搜索树的所有的叶子节点
x
x
x开始,对于所有
x
x
x连出的边(除了连向自己父亲的边),如果这条边的终点的深度小于
x
x
x,那么将这条边对应的无向边的起点设为
x
x
x;然后对于
x
x
x在搜索树中的父亲节点
f
a
fa
fa,根据当前
x
x
x的出度来调整边
<
f
a
,
x
>
<fa,x>
<fa,x>方向。
正确性:
对于你做完的每个点来说,他的出度已经确定了,而他的所有除了根节点以外的祖先都有至少一次的调整出度的机会,而根节点的出度已经被保证了,因为总出度
s
u
m
sum
sum确定(为偶数),除了根节点以外所有点的出度已经确定,他们都是偶数,那么他们的和
s
u
su
su 也是偶数,那么显然根节点出度
s
u
m
−
s
u
sum-su
sum−su也为偶数。
#include<bits/stdc++.h>
#define ll long long
#define pa pair<int,int>
using namespace std;
int n,m;
int cu[200004];
int dir[200004],dep[200004];
vector<int>G[200004];
vector<pa>ans;
void dfs(int x,int fa){
for(int i=0;i<G[x].size();i++){
if(G[x][i]==fa)continue;
if(!dep[G[x][i]]){
dep[G[x][i]]=dep[x]+1;
dfs(G[x][i],x);
}
else if(dep[G[x][i]]<dep[x]){
cu[x]^=1;
ans.push_back(make_pair(x,G[x][i]));
}
}
if(cu[x]&1){
cu[x]^=1;
ans.push_back(make_pair(x,fa));
}
else if(fa){
cu[fa]^=1;
ans.push_back(make_pair(fa,x));
}
}
int main(){
ans.clear();
memset(dep,0,sizeof(dep));
memset(dir,0,sizeof(dir));
memset(cu,0,sizeof(cu));
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int u,v;scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
if(m&1)return puts("-1"),0;
dep[1]=1;
dfs(1,0);
for(int i=0;i<ans.size();i++){
printf("%d %d\n",ans[i].first,ans[i].second);
}
return 0;
}
C.Skolem XOR Tree
题意:
给定一个
n
n
n,然后你构建一个点数为
2
n
2n
2n的树,编号为
i
i
i和
n
+
i
n+i
n+i的点的权值是
i
i
i,然后这个树满足,对于任意
i
i
i,
i
i
i到
n
+
i
n+i
n+i的路径上的点的权值的异或和等于
i
i
i
题解:
首先对于
n
n
n为
2
2
2的幂的情况无解。
然后对于
n
>
=
3
n>=3
n>=3切n为奇数的情况,
由于对于任何偶数
x
x
x,
x
x
x^
1
1
1
=
x
+
1
= x+1
=x+1 同时
(
x
+
1
)
(x+1)
(x+1)^
1
1
1
=
x
= x
=x
那么就把连续的奇偶数字放在一起挂在节点
1
1
1上。
对于偶数的情况,我们先按照奇数来做,最后剩
n
n
n和
2
∗
n
2*n
2∗n,然后你需要找两个数字
a
,
b
a,b
a,b使得
a
a
a ^
1
1
1 ^
b
b
b =
n
n
n 然后把
n
n
n连在与节点
1
1
1直接相连的,权值为
a
a
a的点上,把
2
∗
n
2*n
2∗n连在与节点
1
1
1直接相连的,权值为
b
b
b的点上即可。
#include<bits/stdc++.h>
#define ll long long
#define pa pair<int,int>
using namespace std;
vector<pa>ans;
set<int>tr;
int n;
void output(){
for(int i=0;i<ans.size();i++)printf("%d %d\n",ans[i].first,ans[i].second);
}
int main(){
ans.clear();
scanf("%d",&n);
int p=1;
while(p<=n){
if(n==p)return puts("No"),0;
p<<=1;
}
puts("Yes");
bool flag=0;
if(n%2==0){
flag=1;
}
for(int i=1;i<3;i++){
ans.push_back(make_pair(i,i+1));
ans.push_back(make_pair(i+n,i+1+n));
}
ans.push_back(make_pair(3,n+1));
for(int i=4;i+1<=n;i+=2){
ans.push_back(make_pair(1,i));
ans.push_back(make_pair(i,i+1));
ans.push_back(make_pair(1,i+1+n));
ans.push_back(make_pair(i+n,i+1+n));
}
if(flag){
tr.clear();
for(int i=1;i<n;i++)tr.insert(i);
for(int i=2;i<n;i++){
if(tr.count(n^i^1)){
int a=n^i^1,b=i;
if(a==b)continue;
if(a&1){
ans.push_back(make_pair(a+n,n));
}
else{
ans.push_back(make_pair(a,n));
}
if(b&1){
ans.push_back(make_pair(b+n,2*n));
}
else{
ans.push_back(make_pair(b,2*n));
}
output();
return 0;
}
}
}
else{
output();
}
return 0;
}