zoukankan      html  css  js  c++  java
  • [Lydsy1805月赛] quailty 算法

        稍微建一下模型就可以发现,题目要求的其实是一个最小异或基环森林。。。。

        可以用类似最小生成树的拟阵性质来证明,贪心的从小的边权开始依次尝试加入的方法是对的。

        所以我们把a[]排完序之后直接递归贪心就行了。。。。

        从大的位到小的位考虑,能不选这一位为一的边就不选。

        首先如果区间内不存在这一位为1的边的话是可以不选的;如果把区间内这一位为1的数分成两个子区间(一定是一个前缀一个后缀),并且子区间内元素都>2的话,也是可以不选的;

        其他情况是要选的,可以根据两边子区间的大小来判断选前几小的边。。。

        因为只有一边点数<=2的时候需要 O(左右子区间大小乘积) 的复杂度去计算,所以复杂度是对的。。。。

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int N=300005;
    int n,a[N],T;
    ll ans=0;
    
    inline int read(){
    	int x=0; char ch=getchar();
    	for(;!isdigit(ch);ch=getchar());
    	for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
    	return x;
    }
    
    void solve(int o,int l,int r){
    	if(o<0||l>=r) return;
    	if(r==l+1) { ans+=a[l]^a[r]; return;}
    	
    	int mid;
    	for(mid=l;mid<=r&&((a[mid]>>o)&1)==0;mid++);
    	
    	solve(o-1,l,mid-1),solve(o-1,mid,r);
    	
    	if((mid-l>=3&&r-mid>=2)||mid==l||mid>r) return;
    	
    	int M=1<<30,m=1<<30,now;
    	for(int i=l;i<mid;i++)
    	    for(int j=mid;j<=r;j++){
    	    	now=a[i]^a[j];
    	    	if(now<M) m=M,M=now;
    	    	else if(now<m) m=now;
    		}
    	
    	if(mid-l<=2&&r-mid<=1) ans+=m+(ll)M;
    	else ans+=M;
    }
    
    int main(){
    	T=read();
    	
    	while(T--){
            n=read(),ans=0;
            for(int i=1;i<=n;i++) a[i]=read();
            sort(a+1,a+n+1);
            
            solve(30,1,n);
            
            printf("%lld
    ",ans);
    	}
    	
    	return 0;
    }
    
  • 相关阅读:
    jquery的get方式发送AJAX请求
    原生JS发送AJAX请求
    正则表达式(二)
    正则表达式(一)
    旅游攻略-北京三日游攻略(已实践)
    边旅游边赚钱的噱头,这是一种传销!
    hdu 1106 排序(水题)
    hdu 1258 Sum It Up(dfs+去重)
    hdu 1455 Sticks(dfs+剪枝)
    解决“LINK : fatal error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏”问题
  • 原文地址:https://www.cnblogs.com/JYYHH/p/9192102.html
Copyright © 2011-2022 走看看