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
#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
#define ll long long
#define pa pair
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
#define ll long long
#define pa pair
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;
}