CF1689E ANDfinity 题解

CF1689E ANDfinity 题解

luogu

对于图的连通性,可以用并查集维护(合并成功 n1 次,或者一个集合大小为 n,则整张图已经连通)。

首先有很显然:所有的 0 都要变成 1,因为 0 和任何数按位与都是 0

此时如果整张图已经连通,那么直接结束。

不连通的话呢?有个性质:只通过对偶数的最多两次操作,便一定达成整张图连通

那么为了答案最优,对于一次操作,暴力扫就可以。两次操作的构造方式如下。

方法与证明:

首先所有奇数肯定在同一个连通块里,因为它们二进制形式的末尾是 1。这个连通块内也可能有偶数。

所以除开包含奇数的连通块,其它零散的连通块肯定全是偶数

考虑加一和减一操作对一个偶数二进制形式的影响:

  1. 加一则把偶数的末尾的 0 变成 1
  2. 减一会把它的 lowbit 变成 0,后面的都变成 1

可以看到,加一只会加边不会删边,而减一加的边可能更多但是可能删边

注意第二条,贪心的想,可以把最大的 lowbit 对应的数减一,这样 lowbit 小于它的其它数都会与它连通,并且它们都和奇数连通块连通了。此时场上最多两个连通块,并且一个是包含奇数的连通块,另一个是 lowbit 全都是最大值的连通块,操作的数和此块可能断绝了联系。

同时可以发现,如果最大的 lowbit 只有一个,那么已经连通;如果不含奇数的连通块只有一个,通过加一操作就可以达成连通。这些在之前暴力枚举中已经解决。

如果此时还未整个连通,剩下一个无奇数连通块只要加一,根据前面的讨论,这样只会加边,而且它会带着这个连通块和那个奇数连通块连通,那么此时就达成了目标。

一次操作的已经暴力实现,两次操作的这样一定可以构造出来。

于是就证明完了。

丑陋的代码 qwq:

#include<bits/stdc++.h>
#define EL puts("Elaina")
#define reg register int
typedef long long ll;
using namespace std;
inline char gc(){
    static char buf[1<<20],*p1,*p2;
    if(p1==p2){p1=buf,p2=buf+fread(buf,1,1<<20,stdin);if(p1==p2)return EOF;}
    return *p1++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=gc();}
    while(isdigit(ch))x=(x<<1)+(x<<3)+(ch^48),ch=gc();
    return x;
}
const int maxn=2e3+3;
inline int lowbit(int x){return x&(-x);}
int n,a[maxn],ans,cnt;
struct dsu{
    int fa[maxn],rk[maxn],val[maxn];
    inline void init(int n){
        for(reg i=1;i<=n;++i)fa[i]=i,rk[i]=0,val[i]=a[i];
    }
    inline int find(int x){
        return fa[x]^x?fa[x]=find(fa[x]):x;
    }
    inline bool merge(int x,int y){
        x=find(x),y=find(y);
        if(x==y)return 0;
        if(rk[x]<rk[y])fa[x]=y,rk[y]=max(rk[y],rk[x]+1),val[y]|=val[x];
        else fa[y]=x,rk[x]=max(rk[x],rk[y]+1),val[x]|=val[y];
        return 1;
    }
    inline int value(int x){
        return val[find(x)];
    }
}S;
inline bool link(){
    cnt=0,S.init(n);
    for(reg i=1;i<=n;++i)
        for(reg j=1;j<i;++j)
            if(a[i]&a[j]){
                cnt+=S.merge(i,j);
                if(cnt==n-1)return 1;
            }
    return 0;
}
inline void overdesu(){
    printf("%d\n",ans);
    for(reg i=1;i<=n;++i)
        printf("%d ",a[i]);
    printf("\n");
}
inline void MyDearMomonts(){
    n=read(),ans=0,cnt=0;
    for(reg i=1;i<=n;++i){
        a[i]=read();
        if(!a[i])ans+=++a[i];
    }
    S.init(n);
    if(link()){overdesu();return;}
    for(reg i=1;i<=n;++i){
        a[i]++,ans++;
        if(link()){overdesu();return;}
        a[i]-=2;
        if(link()){overdesu();return;}
        a[i]++,ans--;
    }
    int hib=0;
    for(reg i=1;i<=n;++i)
        hib=max(hib,lowbit(a[i]));
    for(reg i=1;i<=n;++i)
        if(lowbit(a[i])==hib){
            a[i]--,ans++;
            if(link()){overdesu();return;}
            break;
        }
    for(reg i=1;i<=n;++i)
        if(!(S.value(i)&1)){
            a[i]++,ans++,overdesu();
            return;
        }
}
int main(){
    int T=read();
	while(T--)MyDearMomonts();
    return (0^0);
}
posted @   Muel_imj  阅读(87)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构

阅读目录(Content)

此页目录为空

点击右上角即可分享
微信分享提示