zoukankan      html  css  js  c++  java
  • HGOI 20200727

    回归水题大赛

    T1 圆排列(heightround)

    显然最优的排列就是从最小的到最大的的两条上升路径串起来

    考虑二分答案

    对于一个答案t

    我们每次将距离最接近t的点加入,这样可以获得第一个上升路径的最差情况

    然后判断剩余的点能否构成上升路径

    注意到 (check) 得到的第一个路径其实就是答案的后面的路径,这样也可以方便的得出答案

    #include <bits/stdc++.h>
    using namespace std;
    
    #define rep(i, a, b) for (int i = a; i <= b; i++)
    #define per(i, a, b) for (int i = a; i >= b; i--)
    #define siz(a) (int)a.size()
    #define pb push_back
    #define mp make_pair
    #define ll long long
    #define fi first
    #define se second
    
    const int N = 1010 ;
    
    int n, Ans ;
    int a[N], vis[N], ans[N] ;
    
    bool check(int stp) {
    	memset(vis, 0, sizeof(vis)) ;
    	int p = 1 ;
    	rep(i, 2, n) 
    	if (a[i] - a[p] > stp) {
    		if (i == p + 1) return false ;
    		vis[i - 1] = 1 ;
    		p = i - 1 ;
    	}
    	if (a[n] - a[p] > stp) return false ;
    	p = 1 ;
    	rep(i, 2, n - 1) 
    	if (!vis[i]) {
    		if (a[i] - a[p] > stp) return false ;
    		p = i ;
    	}
    	if (a[n] - a[p] > stp) return false ;
    	return true ;
    }
    
    void getans(int stp) {
    	memset(vis, 0, sizeof(vis)) ;
    	int p = 1, id = 0 ;
    	rep(i, 2, n) 
    	if (a[i] - a[p] > stp) {
    		vis[i - 1] = ++id ;
    		p = i - 1 ;
    	}
    	vis[n] = ++id ;
    //	rep(i, 1, n) cout << vis[i] << " " ; cout << endl ;
    	p = n ;
    	per(i, n - 1, 2)
    	if (!vis[i]) {
    		vis[i] = ++id ;
    		p = i ;
    	}
    	vis[1] = ++id ;
    	rep(i, 1, n) ans[vis[i]] = a[i] ;
    	reverse(ans + 1, ans + n + 1) ;
    	rep(i, 1, n) printf("%d ", ans[i]) ; cout << endl ;
    }
    
    signed main() {
    //	freopen("heightround.in", "r", stdin) ;
    //	freopen("heightround.out", "w", stdout) ; 
    	int t ; scanf("%d", &t) ;
    	while (t--) {
    		scanf("%d", &n) ;
    		rep(i, 1, n) scanf("%d", &a[i]) ;
    		sort(a + 1, a + n + 1) ;
    		int l = 0, r = a[n] - a[1] ;
    		Ans = r + 10 ;
    		while (l <= r) {
    			int mid = (l + r) >> 1 ;
    			if (check(mid)) Ans = mid, r = mid - 1 ;
    			else l = mid + 1 ;
    		}
    //		cout << Ans << endl ;
    		getans(Ans) ;
    	}
    	return 0 ;
    }
    

    T2 彩色(color)

    这是一个没什么含金量的题目

    因为 (N) 只有50,考虑暴力作法(可以扫描线+线段树做的)

    首先离散化,然后从后往前记录每一个矩形的获得染色面积

    只需要 (check) 每一个小的离散化矩形有没有被占用即可

    然后 (sort) 找出前 (k) 大取出即可

    #include <bits/stdc++.h>
    using namespace std;
    
    #define rep(i, a, b) for (int i = a; i <= b; i++)
    #define per(i, a, b) for (int i = a; i >= b; i--)
    #define siz(a) (int)a.size()
    #define pb push_back
    #define mp make_pair
    #define ll long long
    #define fi first
    #define se second
    #define x1 __XXX1___
    #define x2 __XXX2___
    #define y1 __YYY1___
    #define y2 __YYY2___
    
    const int N = 1010 ;
    
    struct node {
    	int x1, y1, x2, y2 ; 
    } a[N] ;
    
    int n, k ;
    vector <int> xset, yset ;
    vector <pair<int, int> > ans ;
    int aid[N], filled[N][N] ;
    
    int S(node a) {
    	return (xset[a.x2] - xset[a.x1]) * (yset[a.y2] - yset[a.y1]) ;
    } 
    
    bool cmp(pair <int, int> a, pair <int, int> b) {
    	if (a.fi != b.fi) return a.fi > b.fi ;
    	else return a.se < b.se ;
    }
    
    signed main() {
    //	freopen("color.in", "r", stdin) ;
    //	freopen("color.out", "w", stdout) ; 
    	scanf("%d%d", &n, &k) ;
    	rep(i, 1, n) {
    		scanf("%d%d%d%d", &a[i].x1, &a[i].y1, &a[i].x2, &a[i].y2) ;
    		xset.pb(a[i].x1) ; xset.pb(a[i].x2) ;
    		yset.pb(a[i].y1) ; yset.pb(a[i].y2) ;		
    	}
    	sort(xset.begin(), xset.end()) ;
    	sort(yset.begin(), yset.end()) ;
    	xset.erase(unique(xset.begin(), xset.end()), xset.end()) ;
    	yset.erase(unique(yset.begin(), yset.end()), yset.end()) ;
    	rep(i, 1, n) {
    		a[i].x1 = lower_bound(xset.begin(), xset.end(), a[i].x1) - xset.begin() ;
    		a[i].x2 = lower_bound(xset.begin(), xset.end(), a[i].x2) - xset.begin() ;
    		a[i].y1 = lower_bound(yset.begin(), yset.end(), a[i].y1) - yset.begin() ;
    		a[i].y2 = lower_bound(yset.begin(), yset.end(), a[i].y2) - yset.begin() ;
    	}
    //	for (int i = 0; i < xset.size(); i++) printf("%d ", xset[i]) ; cout << endl ;
    //	for (int i = 0; i < yset.size(); i++) printf("%d ", yset[i]) ; cout << endl ;
    //	rep(i, 1, n) printf("%d %d %d %d
    ", a[i].x1, a[i].x2, a[i].y1, a[i].y2) ;
    	ans.resize(n) ;
    	per(i, n, 1) {
    		ans[i - 1].se = i - 1 ;
    		rep(j, a[i].x1 + 1, a[i].x2)
    		rep(k, a[i].y1 + 1, a[i].y2) {
    			if (!filled[j][k]) ans[i - 1].fi += S((node) {j - 1, k - 1, j, k}) ;
    			filled[j][k] = true ;
    		} 
    	}
    //	rep(i, 0, siz(ans) - 1) cout << ans[i].fi << " " << ans[i].se << endl ;
    	sort(ans.begin(), ans.end(), cmp) ;
    	rep(i, 0, k - 1) aid[i + 1] = ans[i].se ;
    	sort(aid + 1, aid + k + 1) ;
    	rep(i, 1, k) printf("%d ", aid[i]) ; cout << endl ;
    	return 0 ;
    }
    
    

    T3 联络(biu)

    这也是一个很简单的题目

    题目意思是构建补图,然后在同一个连通块的放在同一个集合里

    考虑 (m) 只有 (2000000=(1000)*(2000)/2),因此成为完全图只会有 (2000) 个点左右

    也就意味着 (friend) 最少的点的 (friend) 最多两千左右

    这样我们就可以把最少的点和没有和他一起的点合并

    然后在按照 (O(N^2)) 的方法做

    (n^2) 就是每次加入一个点,看能否更新一些点和他在一起,用并查集维护

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <vector>
    #define rep(i, a, b) for (int i = a; i <= b; i++)
    #define siz(a) a.size()
    using namespace std;
    
    const int N = 100010 ; 
    
    int n, m, ans, cnt, num;
    int map[3010][3010], vis[N], degree[N], pool[N];
    int father[N], p[N], hash1[20010];
    
    vector<int> ch[N];
    
    int get_father(int x) {
        if (x == father[x])
            return x;
        father[x] = get_father(father[x]);
        return father[x];
    }
    
    void merge(int x, int y) {
        x = get_father(x);
        y = get_father(y);
        if (x != y)
            father[y] = x;
    }
    
    bool is_num(char ch) { return ch >= '0' && ch <= '9'; }
    
    void read(int &x) {
        int tmp = 0;
        char ch = getchar();
        while (!is_num(ch)) ch = getchar();
        while (is_num(ch)) {
            tmp *= 10;
            tmp += ch - '0';
            ch = getchar();
        }
        x = tmp;
    }
    
    int main() {
        scanf("%d%d", &n, &m);
        int a, b, k;
        rep(i, 1, n) father[i] = i;
        rep(i, 1, m) {
        	int a, b ; scanf("%d%d", &a, &b) ;
            ch[a].push_back(b);
            ch[b].push_back(a);
            degree[a]++;
            degree[b]++;
        }
        k = 1;
        rep(i, 2, n) if (degree[i] < degree[k]) k = i ;
        int t = ch[k].size();
        cnt = 1;
        rep(i, 0, siz(ch[k]) - 1) vis[ch[k][i]] = 1 ;
    	rep(i, 1, n)
            if (!vis[i]) {
                num++;
                pool[i] = 1;
            } else
                pool[i] = ++cnt;
    	rep(i, 1, n)
        rep(j, 0, siz(ch[i]) - 1)
        if (pool[i] != pool[ch[i][j]]) map[pool[i]][pool[ch[i][j]]]++;
    	rep(i, 1, cnt)
    	rep(j, 1, cnt)
        if (i != j) {
            if (j == 1 && map[i][j] < num) merge(j, i);
            if (j != 1 && !map[i][j]) merge(i, j);
        }
    	rep(i, 1, cnt) p[get_father(i)]++;
    
        p[1] += num - 1;
    	rep(i, 1, cnt) if (p[i]) hash1[++ans] = p[i];
        printf("%d
    ", ans);
        sort(hash1 + 1, hash1 + ans + 1);
        rep(i, 1, ans - 1) printf("%d ", hash1[i]);
        printf("%d
    ", hash1[ans]);
    
        return 0;
    }
    
  • 相关阅读:
    Xposed模块开发基本方法记录
    Win8.1下运行环境/配置问题解决方案总结
    wordpress安装记录
    编译时:virtual memory exhausted: Cannot allocate memory
    Support for AMD usage of jwplayer (require js)
    UC 浏览器远程调试手机web网页记录
    手机浏览器页面点击不跳转(Android手机部分浏览器) 浏览器双击放大网页 解决
    aes 加密,解密(2)
    aes 加密,解密
    ionic 安装步骤
  • 原文地址:https://www.cnblogs.com/harryhqg/p/13384840.html
Copyright © 2011-2022 走看看