找结论--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 */