找结论--ANDfinity+wintersrain邻接链表维护连通性

题目描述
给出一个序列 aa, 两个位置如果 andand 值大于 00 则这两个点有边,每次操作可以把一个数字加一或者减一,问最少操作多少次可以使 nn 个点连通

lowbit
对于一组数
先把0+1 
如果就已经联通了
直接输出
否则 
找出maxlowbit
如果只有1个
直接maxlowbit-1
一定可以和其他联通 
如果多个 
找出两个
(A,B,{C_lowbitmax},{D_lowbitother})
A-1 ---D
C--B+1--A
还有特殊数据
8 8 1
所以直接暴力搜索+1或者-1 
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<string>
#include<cstdlib>
#include<ctime>
#include<algorithm>
#include<iomanip>
#include<bitset>
#include<map>
#include<queue>
#include<bitset>
#include<deque>
#include<vector>
#define _f(i,a,b)  for(register int i=a;i<=b;++i)

#define f_(i,a,b)  for(register int i=a;i>=b;--i)

#define ll long long

#define chu printf


using namespace std;
inline int re()
{
    int x = 0, f = 1;
    char ch = getchar();
    while(ch > '9' || ch < '0')
    {
        if(ch == '-')
        {
            f = -1;
        }
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}
const int WR=1001000;int INF=1e9; 
int fa[2100];
int fa2[2100];
inline int getfa(int x)
{
    if(fa[x]!=x)return fa[x]=getfa(fa[x]);
    return x;
}
int a[2100];
inline void insert(int x,int y)
{
    int fax=getfa(x),fay=getfa(y);
    fa[fax]=fay;
}
inline int lowbit(int x)
{
    return x&(-x);
}
inline void deal()
{
    int n=re();
    int step=0;
    _f(i,1,n)
    {
        a[i]=re(),fa[i]=i,fa2[i]=i;
        if(a[i]==0)a[i]=1,step++;
    }
    _f(i,1,n)
    {
        _f(j,1,n)
        {
            if(i==j)continue;
            if(a[i]&a[j])insert(i,j);
        }
    }
    int grandfa=getfa(1);//随便找个位置 
    _f(i,2,n)//自然连通 
    {
        if(getfa(i)!=grandfa)break;
        if(i==n)//恭喜所有联通!!
        {
            chu("%d\n",step);
            _f(o,1,n)chu("%d ",a[o]);
            chu("\n");    
            return;
        } 
    }//先枚举每个lowbit最大的数字+1/-1行不行
    int maxlow=0;//决策1 
    _f(i,1,n)
    {
        int sco=lowbit(a[i]);
        if(sco>maxlow)maxlow=sco;
    }
    vector<int>ans;
    ans.clear();
    _f(i,1,n)
    {
        if((a[i]&(-a[i]))==maxlow)ans.push_back(i);
     } 
     int siz=ans.size();
     _f(i,0,siz-1)
     {
     //    if(a[ans[i]]&(-a[ans[i]])!=maxlow)continue;
         a[ans[i]]+=1;
         step++;
         _f(j,1,n)
         _f(k,1,n)
         {
             if(j==k)continue;
             if(a[j]&a[k])insert(j,k);
         }
         bool can=true;
         int gfa=getfa(1);
         _f(j,2,n)
         if(getfa(j)!=gfa)
         {
             can=false;break;
         }
        if(can==true)
        {
            chu("%d\n",step);
            _f(p,1,n)chu("%d ",a[p]);
            chu("\n");return;
        }
        a[ans[i]]-=2;
        _f(iop,1,n)fa[iop]=iop;
        _f(j,1,n)
        _f(k,1,n)
        {
            if(j==k)continue;
            if(a[j]&a[k])insert(j,k);
        }
        can=true;
        gfa=getfa(1);
        _f(j,2,n)if(getfa(j)!=gfa){
            can=false;break;
        }
        if(can==true)
        {
            chu("%d\n",step);
            _f(p,1,n)chu("%d ",a[p]);
            chu("\n");return;
        }
        a[ans[i]]+=1;
        step-=1;
        _f(iop,1,n)fa[iop]=iop;
     }
    //那就是有很多lowbit,需要特殊讨论的枚举 ,随便来一个 
    a[ans[0]]-=1;
    a[ans[1]]+=1;
    step+=2;
    chu("%d\n",step);
    _f(i,1,n)chu("%d ",a[i]);
    chu("\n");
}
int main()
{
    int t=re();
    while(t--)
    {
        deal();
    }
    return 0;
}
/*


4
5
1 2 3 4 5
2
0 2
2
3 12
4
3 0 0 0

1


0
1 2 3 4 5
2
2 2
1
3 11
3
3 1 1 1

5
5
1 2 3 4 5
2
0 2
2
3 12
4
3 0 0 0
3
8 8 1

*/

还有史一鸣的代码

用了类似邻接链表的方式

去找连通性

本质就是:

如果连通。那么所有的涉及到的1位一定可以一次性通过一个数遍历到

bit[i]就存储对于每个i位

可以到达哪些位

用每个数去更新

O(n*log(n))优秀

#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
#include<algorithm>
#define int long long
#define WR WinterRain
using namespace std;
const int WR=5010,mod=1e9+7;
int t;
int n,ans,a[WR];
int bit[WR/50][WR];
bool flag[WR/50];
int read(){
    int s=0,w=1;
    char ch=getchar();
    while(ch>'9'||ch<'0'){
        if(ch=='-') w=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        s=(s<<3)+(s<<1)+ch-48;
        ch=getchar();
    }
    return s*w;
}
inline void tag(int u)
{
    if(flag[u])return;
    flag[u]=true;
    for(int i=1;i<=bit[u][0];i++)
    {
        tag(bit[u][i]);
    }
}
inline bool judge()
{
    memset(bit,0,sizeof(bit));
    memset(flag,0,sizeof(flag));
    int s=0;
    for(int i=1;i<=n;i++)
    {
        if(!a[i])return false;
        s=a[i]|s;
    }
    for(int i=1;i<=n;i++)
    {
        int pre=-1;
        for(int j=0;j<=30;j++)
        {
            if(a[i]&(1<<j))
            {
                if(pre>=0)
                {
                    bit[pre][0]++;bit[j][0]++;
                    bit[pre][bit[pre][0]]=j;
                    bit[j][bit[j][0]]=pre;
                }
                pre=j;
            }
        }
    }
    for(int i=0;i<=30;i++)
    {
        if(s&(1<<i))
        {
            tag(i);
            break;
        }
    }
    for(int i=0;i<=30;i++)
    if(!flag[i]&&(s&(1<<i)))return false;
    return true;
}
int lowbit(int x){
    return x&(-x);
}
signed main(){
    t=read();
    while(t--){
        n=read();
        bool tag=false;
        for(int i=1;i<=n;i++) a[i]=read();
        ans=0;
        for(int i=1;i<=n;i++){
            if(!a[i]) ans++,a[i]++;
        }
        if(judge()){
            printf("%lld\n",ans);
            for(int i=1;i<=n;i++){
                printf("%lld ",a[i]);
            }
            printf("\n");
            continue;
        }
        for(int i=1;i<=n;i++){
            a[i]--;
            if(judge()){
                printf("%lld\n",ans+1);
                for(int j=1;j<=n;j++){
                    printf("%lld ",a[j]);
                }
                printf("\n");
                tag=true;
                break;
            }
            a[i]++;
        }
        if(tag) continue;
        for(int i=1;i<=n;i++){
            a[i]++;
            if(judge()){
                printf("%lld\n",ans+1);
                for(int j=1;j<=n;j++){
                    printf("%lld ",a[j]);
                }
                printf("\n");
                tag=true;
                break;
            }
            a[i]--;
        }
        if(tag) continue;
        int low=0;
        for(int i=1;i<=n;i++) low=max(low,lowbit(a[i]));
        for(int i=1;i<=n;i++){
            if(lowbit(a[i])==low){
                a[i]--;
                break;
            }
        }
        for(int i=1;i<=n;i++){
            if(lowbit(a[i])==low){
                a[i]++;
                break;
            }
        }
        printf("%lld\n",ans+2);
        for(int i=1;i<=n;i++){
            printf("%lld ",a[i]);
        }
        printf("\n");
    }
    return 0;
}
/*
1
4
19
5
4
34

*/

 

posted on 2022-06-15 18:57  HZOI-曹蓉  阅读(36)  评论(0编辑  收藏  举报