1 条题解
-
0
自动搬运
来自洛谷,原作者为

EXODUS
I love you this much搬运于
2025-08-24 22:34:48,当前版本为作者最后更新于2022-09-03 21:32:44,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
Part 1:前言
图论建模好题!
Part 2:正文
首先观察题目中所给的条件
在这里不妨令 ,将其分解为二进制,并把位数对齐,在这里我们假设 分解后的结果如下。
不难发现这是一种符合条件的情况,你发现了什么?
首先摆出结论,令 表示 的最高位 的位置(从高位到低位), 表示 的第 位是否是 ,则有 。
考虑如何证明,若 ,则异或后结果的第 位必然是 ,由于异或后第 位与异或前的均相同,所以此时有 。此时如果暴力建边,可以通过维护并查集的方式维护连通块。
注意到 与 互为充要条件,所以我们可以多维护 个并查集,分别表示每一位,然后对每一位 记录是否存在 使得 以及是否存在 使得 。接下来对于每个 ,判断他所有有 的位 是否存在 ,使得 ,以及对其最高位 是否存在 使得 ,由于上述的处理,这个可以 做到。如果存在上述两种情况的话就直接合并它与对应位数的并查集。
输出的时候直接输出该并查集中的 的和,带权并查集解决。由于我没写按秩合并,所以时间复杂度是 的。
Part 3:代码
bool DataS=0,FilE=0; int T; void init(){ return; } const int N=2e5+7,B=37; int n; int a[N],b[N]; int fa[N],sum[N],hib[N]; bool vis1[N],vis2[N]; int find(int i){while(i!=fa[i])i=fa[i]=fa[fa[i]];return i;} void merge(int x,int y){x=find(x),y=find(y);if(x==y)return;fa[x]=y,sum[y]+=sum[x];} signed main(){ if(FilE){ freopen("test.in","r",stdin); freopen("test.out","w",stdout); } T=(DataS?read():1); while(T--){ init(); n=read(); for(int i=1;i<=n;i++)a[i]=read(); for(int i=1;i<=n;i++){ b[i]=read(); fa[i]=i,sum[i]=b[i]; } int bit=30; for(int i=1;i<=bit+1;i++)fa[i+n]=i+n; for(int i=1;i<=n;i++){ for(int j=bit,flag=1;~j;j--){ if((a[i]&(1<<j))&&flag)vis1[j]=1,flag=0,hib[i]=j; if((!(a[i]&(1<<j)))&&(!flag))vis2[j]=1; } } for(int i=1;i<=n;i++){ if(vis2[hib[i]])merge(i,hib[i]+n+1); for(int j=hib[i],flag=1;~j;j--){ if(!(a[i]&(1<<j))&&vis1[j])merge(i,j+n+1); } } for(int i=1;i<=n;i++){ int x=find(i); printf("%lld\n",sum[x]); } } return 0; }Part 4:后文
点赞再走吧(可怜
- 1
信息
- ID
- 7315
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 4
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者