当前位置:   article > 正文

Codeforces Round #647 (Div. 1) C - Necklace(欧拉回路+异或性质+虚点+缩点+lambda表达式的写法)_欧拉回路 codeforces

欧拉回路 codeforces

题目

n(n<=5e5)段项链,第i段左端ai右端bi(0<ai,bi<2^20),

两段项链ij可以拼接在一起,中间产生的值是i的一端u和j的一端v所产生的贡献,

贡献计算方式是最大的k,满足(u^v)%(1<<k)=0,即最大的k满足2的k次方能被u异或v的值整除,

特别的,如果u=v,k被记作20,

要求把i串项链串成一串项链时,链上最小的贡献的最大

输出这个贡献,并输出最终的项链上的珠子是怎么摆放的,第i段左端珠子边号2*i,右端边号2*i+1

思路来源

https://www.cnblogs.com/heyuhhh/p/13051654.html

题解

考虑(u^v)%(1<<k)=0,有u%(1<<k)=v%(1<<k)

由于k最大为20,倒序枚举k,如果项链i一端和项链j一端的%(1<<k)余数相同说明可连,

为了防止连过多边,建完全剩余系虚点[0,(1<<k)-1],由u连向u%(1<<k),v连向v%(1<<k)

此外,由于u-v是原项链上的链,必经,所以把第i条项链u-v这一条边缩成一个点i,

为了防止点号冲突,对点i的点号加1<<k处理

这样从原项链走到另一条项链,对应了走向虚点和从虚点出来两条边,

这样建好图之后,要构成一个环,就是访问图上所有边的欧拉回路问题

因为图里的边号都是一个虚点一个实点,实点只有一条边,所以令边号=实点号,这样方便输出实点号

代码

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<vector>
  5. #include<cmath>
  6. #include<set>
  7. #include<algorithm>
  8. #include<functional>
  9. using namespace std;
  10. typedef pair<int,int> P;
  11. #define rep(i,a,b) for(int i=(a);i<=(b);++i)
  12. #define per(i,a,b) for(int i=(a);i>=(b);--i)
  13. #define sci(x) scanf("%d",&(x))
  14. #define pb push_back
  15. #define fi first
  16. #define se second
  17. const int N=5e5+10;
  18. int n,a[N],b[N];
  19. int main()
  20. {
  21. scanf("%d",&n);
  22. rep(i,0,n-1)sci(a[i]),sci(b[i]);
  23. per(k,20,0){
  24. int up=1<<k;
  25. vector<vector<P> > e(up+n);//a[i]-b[i] 看成一个点i 连向对应的只需低k位的虚点
  26. rep(i,0,n-1){//(u^v)%(1<<k)==0 (u%(1<<k))==(v%(1<<k))
  27. e[a[i]&(up-1)].pb(P(i+up,2*i));//2*i 既是点号也是边号
  28. e[i+up].pb(P(a[i]&(up-1),2*i));//为了防止点号冲突 对i加up处理
  29. e[b[i]&(up-1)].pb(P(i+up,2*i+1));
  30. e[i+up].pb(P(b[i]&(up-1),2*i+1));
  31. }
  32. bool ok=1;
  33. rep(i,0,up+n-1){//奇度 无解
  34. if(e[i].size()%2){
  35. ok=0;
  36. break;
  37. }
  38. }
  39. if(!ok)continue;
  40. vector<int> ans;
  41. vector<bool> vis(2*n);
  42. function <void(int,int)> dfs=[&](int u,int fa){//lambda表达式
  43. while(e[u].size()){
  44. P x=e[u].back();e[u].pop_back();//弧优化
  45. int v=x.fi,id=x.se;
  46. if(!vis[id]){
  47. vis[id]=1;
  48. dfs(v,id);
  49. }
  50. }
  51. if(fa!=-1)ans.pb(fa);//既是当前边号 也是一端的点号
  52. };
  53. rep(i,0,up+n-1){
  54. if(e[i].size()){
  55. dfs(i,-1);
  56. break;
  57. }
  58. }
  59. if(ans.size()<2*n)continue;//图不连通 无解
  60. printf("%d\n",k);
  61. for(auto x:ans){
  62. printf("%d ",x+1);
  63. }
  64. puts("");
  65. break;
  66. }
  67. return 0;
  68. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/1015949
推荐阅读
相关标签
  

闽ICP备14008679号