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\n", 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\n", ans);
    sort(hash1 + 1, hash1 + ans + 1);
    rep(i, 1, ans - 1) printf("%d ", hash1[i]);
    printf("%d\n", hash1[ans]);

    return 0;
}

猜你喜欢

转载自www.cnblogs.com/harryhqg/p/13384840.html