• CodeForces 1361C


    zszz按照传统在写题解之前是要写一堆废话的对不对

    悲惨的回忆……

    被卡科技了/kk,wtcl/dk

    哪个神仙能想到这是个欧拉回路啊/kel

    话说为啥有210个测试点啊,爪巴(

    跑了整整20min了才测好一半,不等了睡觉去了,差评(

    早上看AC了,原来昨天那个时候有比赛。。


    先咕着,等eJOI切完了再来填坑

    UPD 2020.7.24:前来填坑。

    洛谷题目页面传送门 & CF题目页面传送门

    给定(n)个珠子无序对,第(i)个珠子对的权值为((a_i,b_i)),每对的两个珠子已经连了起来。要求再连(n)条线,使(2n)个珠子连成简单环,其中对于每个珠子对,连接它的两条线分别与两个珠子相连。每条再连的线的权值为使得(2^x)能被它所连的两个珠子的权值的异或和整除的最大自然数(x)。你需要最大化再连的(n)条线的最小权值,并给出此时的连接方案。

    (ninleft[1,5 imes10^5 ight],a_i,b_iinleft[0,2^{20} ight))

    首先注意到,答案最多只有(21)种((0sim 20)),我们可以从大到小贪心地枚举答案,转最优化为判定。

    考虑对于(vin[0,20]),如何判定答案是否(geq v)。注意到,要求所有再连的边的最小权值(geq v),就是所有再连的边的权值都要(geq v)。设连的两个珠子权值分别为(x,y),那么即(2^vmid xoplus y),即(xmod 2^v=ymod 2^v)。不难想到,可以将每个珠子的权值当作((a/b)_imod 2^v),这样有解当且仅当可以使得每条再连的线的两端权值相等。

    这样就不难想到图论了。考虑在每个珠子对之间连边,这样最终肯定要每条边都走一遍,并回到自己,不难想到欧拉回路。那么如何体现“再连的线的两端权值相等”这个条件呢?我们把每个珠子映射到它的权值再建图即可,这样每两条相邻走过的边的交点,表示这两个珠子对连接的地方的左右两端的权值是这个同一个数。

    这样,判一下,如果有欧拉回路,DFS的时候就逆序记录经过的边们连接的珠子对,最后将这个大小为(2n)的答案序列reverse即可。

    时间复杂度(mathrm O((n+v)log v)),其中(v)是值域大小,(log)是枚举答案。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define pb push_back
    #define mp make_pair
    #define X first
    #define Y second
    const int N=500000,A_I=1<<20;
    int n;
    int a[N+1],b[N+1];
    vector<pair<int,pair<int,int> > > nei[A_I];
    vector<int> reg[A_I];
    vector<bool> ban[A_I];
    int now[A_I];//当前弧 
    vector<int> pa;
    void dfs(int x=a[1]){//跑欧拉回路 
    //	cout<<x<<" ";
    	for(int &i=now[x];i<nei[x].size();i++)if(!ban[x][i]){
    		int y=nei[x][i].X,y1=nei[x][i].Y.X,y2=nei[x][i].Y.Y;
    		ban[x][i]=ban[y][reg[x][i]]=true;
    		dfs(y);
    		pa.pb(y2);pa.pb(y1);//逆序压入 
    	}
    }
    void sol(int x){
    	for(int i=1;i<=n;i++)a[i]%=1<<x,b[i]%=1<<x;
    	for(int i=0;i<1<<x;i++)nei[i].clear(),reg[i].clear(),ban[i].clear();
    	for(int i=1;i<=n;i++){//建图 
    		if(a[i]==b[i]){
    			nei[a[i]].pb(mp(a[i],mp(2*i-1,2*i)));nei[a[i]].pb(mp(a[i],mp(2*i,2*i-1)));
    			reg[a[i]].pb(nei[a[i]].size()-1);reg[a[i]].pb(nei[a[i]].size()-2);
    		}
    		else{
    			nei[a[i]].pb(mp(b[i],mp(2*i-1,2*i)));nei[b[i]].pb(mp(a[i],mp(2*i,2*i-1)));
    			reg[a[i]].pb(nei[b[i]].size()-1);reg[b[i]].pb(nei[a[i]].size()-1);
    		}
    		ban[a[i]].pb(false);ban[b[i]].pb(false);
    	}
    	for(int i=0;i<1<<x;i++)if(nei[i].size()%2)return;//判欧拉回路 
    	memset(now,0,sizeof(now));pa.clear();
    	dfs(); 
    //	puts("");
    	if(pa.size()!=2*n)return;//图要连通 
    	cout<<x<<"
    ";
    	for(int i=2*n-1;~i;i--)printf("%d ",pa[i]);//倒序 
    	exit(0);
    }
    int main(){
    	cin>>n;
    	for(int i=1;i<=n;i++)scanf("%d%d",a+i,b+i);
    	for(int i=20;;i--)sol(i);//从大到小枚举答案 
    	return 0;
    }
    
  • 相关阅读:
    MySQLCluster架构图文详解
    Request.ServerVariables大全,写到这里方便查找
    如何修改表的标识列
    如何在存储过程中,调用另一存储过程的结果集
    自我简介
    第二个web网页
    第一个网页感想
    C语言I博客作业03
    ES基本搜索(1)
    ES的入门学习
  • 原文地址:https://www.cnblogs.com/ycx-akioi/p/CodeForces-1361C.html
Copyright © 2020-2023  润新知