【学习笔记】CF1305 Kuroni and Antihype
想了一下,觉得还是发单篇的题解比较合理
怎么感觉这题之前做过
先抛开建边方式不管 这一步其实挺重要的,但是可能大多数人独立做这道题的时候都在想用位运算的性质,而没有想到分开考虑吧?,考虑新建 
     
      
       
       
         0 
        
       
      
        0 
       
      
    0号节点,问题转化为如果 
     
      
       
        
        
          a 
         
        
          i 
         
        
       
          and  
        
        
        
          a 
         
        
          j 
         
        
       
         = 
        
       
         0 
        
       
      
        a_i\ \text{and}\ a_j=0 
       
      
    ai and aj=0,那么存在 
     
      
       
       
         i 
        
       
         → 
        
       
         j 
        
       
      
        i\to j 
       
      
    i→j的长度为 
     
      
       
        
        
          a 
         
        
          j 
         
        
       
      
        a_j 
       
      
    aj的边,以及 
     
      
       
       
         j 
        
       
         → 
        
       
         i 
        
       
      
        j\to i 
       
      
    j→i的长度为 
     
      
       
        
        
          a 
         
        
          i 
         
        
       
      
        a_i 
       
      
    ai的边,求以 
     
      
       
       
         0 
        
       
      
        0 
       
      
    0为根节点的最大树形图。
观察发现边权和等于将每条边看成 a i + a j a_i+a_j ai+aj求和后再减去 ∑ a i \sum a_i ∑ai,因此无向图的生成树也对应一个树形图。
因此可以直接跑 
     
      
       
       
         kruskal 
        
       
      
        \text{kruskal} 
       
      
    kruskal算法。从大到小枚举边权,然后枚举子集,注意一下细节应该可以通过。复杂度 
     
      
       
       
         O 
        
       
         ( 
        
        
        
          3 
         
        
          18 
         
        
       
         ) 
        
       
      
        O(3^{18}) 
       
      
    O(318)。时限开3s还是比较稳的
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int cnt[1<<18],vs[1<<18];
int n,m,fa[1<<18],a[1<<18];
ll res;
int find(int x){
	return fa[x]==x?x:fa[x]=find(fa[x]);
}
void unionset(int x,int y){
	int u=find(x),v=find(y);
	if(u!=v){
		m-=cnt[u]+cnt[v]-1;
		res+=(ll)(cnt[u]+cnt[v]-1)*(x|y);
		fa[u]=v,cnt[v]=1;
	}
}
int main(){
	cin>>n;
	cnt[0]++;
	for(int i=0;i<1<<18;i++)fa[i]=i,vs[i]=0;
	for(int i=1;i<=n;i++){
		cin>>a[i],cnt[a[i]]++;
	}
	for(int i=(1<<18)-1;i>=0;i--){
		for(int j=i;j;j=(j-1)&i){
			if(cnt[j]&&cnt[i-j]){
				unionset(j,i-j);
			}
		}
	}
	for(int i=1;i<=n;i++)res-=a[i];
	cout<<res;
}

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号