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

    BZOJ5362: [Lydsy1805月赛]quailty 算法

    https://lydsy.com/JudgeOnline/problem.php?id=5362

    分析:

    • 题意即求一个最小基环树森林,两点之间边权为异或值。
    • 这题的思路很好,先排序,我们二进制分组,将(0)(1)分成两部分,显然这两部分之间的边能不连就不连。
    • 但也有必须连的情况,就是出现某个集合大小小于等于(2)的情况,内部无法自身构成基环树,需要和另外一个集合连边,此时我们暴力找最小的边即可。
    • 时间复杂度为(O(nlogn))

    代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    #define N 300050
    typedef long long ll;
    int n,a[N],k=30;
    ll ans;
    void solve(int l,int r,int d) {
    	if(d==-1||l>=r) return ;
    	if(l==r-1) {ans+=a[l]^a[r]; return ;}
    	int mid=l,i,j;
    	for(;mid<=r&&!((a[mid]>>d)&1);mid++) ;
    	solve(l,mid-1,d-1);
    	solve(mid,r,d-1);
    	int ls=mid-l,rs=r-mid+1;
    	if(ls>2&&rs>2) return ;
    	if(ls<1||rs<1) return ;
    	int mn1=1<<30,mn2=1<<30;
    	for(i=l;i<mid;i++) {
    		for(j=mid;j<=r;j++) {
    			int x=a[i]^a[j];
    			if(x<mn1) mn2=mn1,mn1=x;
    			else if(x<mn2) mn2=x;
    		}
    	}
    	if(ls<=2&&rs<=2) ans+=mn1+mn2;
    	else ans+=mn1;
    }
    int main() {
    	int T;
    	scanf("%d",&T);
    	while(T--) {
    		scanf("%d",&n);
    		int i;
    		for(i=1;i<=n;i++) scanf("%d",&a[i]);
    		sort(a+1,a+n+1);
    		ans=0;
    		solve(1,n,k);
    		printf("%lld
    ",ans);
    	}
    }
    
    
    
  • 相关阅读:
    Android Studio快捷键
    Eclipse常用快捷键
    沉浸式状态栏
    JAVA起名规范
    c语言求数组长度
    自定义checkbox风格
    退出所有应用,监控打开了什么活动
    android权限大全
    广播接收者Receiver
    ImageView的常用属性
  • 原文地址:https://www.cnblogs.com/suika/p/10165821.html
Copyright © 2011-2022 走看看