Codeforces 1361C - Johnny and Megan's Necklace(欧拉回路)
阅读原文时间:2023年07月09日阅读:1

Codeforces 题目传送门 & 洛谷题目传送门

u1s1 感觉这个题作为 D1C 还是蛮合适的……

首先不难发现答案不超过 \(20\),所以可以直接暴力枚举答案并 check 答案是否合法,当然二分也是没问题的,转最优性问题为判定性问题。

考虑怎样判断一个答案 \(k\) 是否合法,由于所有相连的线 \(u,v\) 都有 \(2^k\mid a_u\oplus a_v\),那么 \(a_u\bmod 2^k=a_v\bmod 2^k\) 一定成立。因此我们可以将每个点的权值看作 \(a_i\bmod 2^k\),我们要找出一个串珠子的方法使得每条线的两端权值相等。

我们考虑将此题转化为一个图论问题,对于已经连上线的两点 \(a_i,b_i\),连一条 \(a_i\bmod 2^k\) 与 \(b_i\bmod 2^k\) 的无向边。不难想到欧拉回路。当我们经过 \(a_i\bmod 2^k\) 与 \(b_i\bmod 2^k\) 的边的时候相当于将珠子 \(2i+1,2i+2\) 与刚才串好的线连在了一起。那么如何体现”每条新连的线两端权值相等“呢?不难发现,假设我们先访问了 \(a_i\bmod 2^k\to b_i\bmod 2^k\),紧接着访问了 \(a_j\bmod 2^k\to b_i\bmod 2^k\),那么必须有 \(b_i\bmod 2^k=a_j\bmod 2^k\),这就天然地规定了它们的权值必须相等。因此只需检验建出来的图中是否存在欧拉回路即可。根据”每个点度数都是偶数,并且图须为连通图“即可检验。

找到最大的 \(k\) 后还是按照上述方式建图并跑一遍欧拉回路即可找出方案。

#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,63,sizeof(a))
#define pb push_back
#define ppb pop_back
#define mp make_pair
template<typename T1,typename T2> void chkmin(T1 &x,T2 y){if(x>y) x=y;}
template<typename T1,typename T2> void chkmax(T1 &x,T2 y){if(x<y) x=y;}
typedef pair<int,int> pii;
typedef long long ll;
typedef unsigned int u32;
typedef unsigned long long u64;
namespace fastio{
    #define FILE_SIZE 1<<23
    char rbuf[FILE_SIZE],*p1=rbuf,*p2=rbuf,wbuf[FILE_SIZE],*p3=wbuf;
    inline char getc(){return p1==p2&&(p2=(p1=rbuf)+fread(rbuf,1,FILE_SIZE,stdin),p1==p2)?-1:*p1++;}
    inline void putc(char x){(*p3++=x);}
    template<typename T> void read(T &x){
        x=0;char c=getchar();T neg=0;
        while(!isdigit(c)) neg|=!(c^'-'),c=getchar();
        while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
        if(neg) x=(~x)+1;
    }
    template<typename T> void recursive_print(T x){if(!x) return;recursive_print(x/10);putc(x%10^48);}
    template<typename T> void print(T x){if(!x) putc('0');if(x<0) putc('-'),x=~x+1;recursive_print(x);}
    void print_final(){fwrite(wbuf,1,p3-wbuf,stdout);}
}
const int MAXN=5e5;
const int MAXMSK=1<<20;
int n,a[MAXN+5],b[MAXN+5];
vector<int> nei[MAXMSK+5];
bool vis[MAXMSK+5];
void dfs(int x){
    if(vis[x]) return;vis[x]=1;
    for(int i=0;i<nei[x].size();i++) dfs(nei[x][i]);
}
int hd[MAXMSK+5],to[MAXN*2+5],nxt[MAXN*2+5],idu[MAXN*2+5],idv[MAXN*2+5],ec=1;
bool used[MAXN*2+5];
vector<int> ret;
void adde(int u,int v,int x,int y){
    to[++ec]=v;idu[ec]=x;idv[ec]=y;nxt[ec]=hd[u];hd[u]=ec;
}
void cir(int x){
    for(int &e=hd[x];e;e=nxt[e]) if(!used[e>>1]){
        used[e>>1]=1;int u=idu[e],v=idv[e];
        cir(to[e]);ret.pb(v);ret.pb(u);
    }
}
void end(int x){
    int lim=(1<<x)-1;
    for(int i=1;i<=n;i++){
        adde(a[i]&lim,b[i]&lim,i*2-1,i*2);
        adde(b[i]&lim,a[i]&lim,i*2,i*2-1);
    } cir(a[1]&lim);
    printf("%d\n",x);
    for(int u:ret) printf("%d ",u);
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d%d",&a[i],&b[i]);
    for(int i=20;i;i--){
        int lim=(1<<i)-1;
        for(int j=0;j<=lim;j++) nei[j].clear(),vis[j]=0;
        for(int j=1;j<=n;j++){
            nei[a[j]&lim].pb(b[j]&lim);
            nei[b[j]&lim].pb(a[j]&lim);
        } bool flg=1,hav=0;
        for(int j=0;j<=lim;j++) if(nei[j].size()&1){flg=0;break;}
        for(int j=0;j<=lim;j++) if(nei[j].size()>=1&&!vis[j]){
            if(hav){flg=0;break;}hav=1;dfs(j);
        }
        if(flg){end(i);return 0;}
    } end(0);
    return 0;
}

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章