AtCoder Regular Contest 103 构造专场?

版权声明:xgc原创文章,未经允许不得转载。 https://blog.csdn.net/xgc_woker/article/details/82904752

这场比赛除了T1全是构造题耶。。。
构造专场???


T1
给你n个数,要求奇数位,所有数相同,偶数位所有数相同,且相邻两个数不同,最少需要改变多少个数。


一开始题意看错求了个中位数。。。
其实你只用维护一个奇数位出现次数的最大值,次大值,偶数位出现次数的最大值,次大值即可。


#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
typedef long long LL;
int _min(int x, int y) {return x < y ? x : y;}
int _max(int x, int y) {return x > y ? x : y;}
int read() {
	int s = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
	return s * f;
}

int a[110000], b[110000];

int main() {
	int n = read();
	for(int i = 1; i <= n; i++) {
		int x = read();
		if(i & 1) a[(i + 1) / 2] = x;
		else b[i / 2] = x;
	} sort(a + 1, a + n / 2 + 1), sort(b + 1, b + n / 2 + 1);
	int max1 = 0, p1, max2 = 0, p2, max3 = 0, p3, max4 = 0, p4, cc = 1;
	for(int i = 2; i <= n / 2 + 1; i++) {
		if(a[i] == a[i - 1]) cc++;
		else {
			if(cc > max1) max2 = max1, max1 = cc, p2 = p1, p1 = a[i - 1];
			else if(cc > max2) max2 = cc, p2 = a[i - 1];
			cc = 1;
		}
	} cc = 1;
	for(int i = 2; i <= n / 2 + 1; i++) {
		if(b[i] == b[i - 1]) cc++;
		else {
			if(cc > max3) max4 = max3, max3 = cc, p4 = p3, p3 = b[i - 1];
			else if(cc > max4) max4 = cc, p4 = b[i - 1];
			cc = 1;
		}
	} if(p1 != p3) printf("%d\n", n - max1 - max3);
	else {
		printf("%d\n", _min(n - max1 - max4, n - max3 - max2));
	}
	return 0;
}


T2
给你n个点,对于所有的点都从起点(0,0)出发,它们第i步走的长度都是一样的,但方向可以不同,最多走40步,每一步长度不超过1e12。


我们考虑这样一种方法的正确性。
从2 ^ 30开始往 2 ^ 0枚举,每次给绝对值较大的减去或加上 2 ^ k,那你想,这样子每一次加减完之后x和y都会控制在2 ^ k以内,最后肯定是能减完的。
但有一个要注意的,就是你这样走出来是奇数步,到最后偶数步点不能走完,判一下就可以了。


#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
typedef long long LL;
int _min(int x, int y) {return x < y ? x : y;}
int _max(int x, int y) {return x > y ? x : y;}
int read() {
	int s = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
	return s * f;
}

struct node {
	int x, y;
} a[1100];
char ans[1100][41];
int n, now, D[40];

void solve(int x) {
	++now; D[now] = x;
	for(int i = 1; i <= n; i++) {
		if(abs(a[i].x) > abs(a[i].y)) {
			if(a[i].x > 0) ans[i][now] = 'R', a[i].x -= x; 
			else ans[i][now] = 'L', a[i].x += x;
		} else {
			if(a[i].y > 0) ans[i][now] = 'U', a[i].y -= x;
			else ans[i][now] = 'D', a[i].y += x;
		}
	}
}

int main() {
	n = read();
	for(int i = 1; i <= n; i++) a[i].x = read(), a[i].y = read();
	for(int i = 30; i >= 0; i--) solve(1 << i);
	if(a[1].x || a[1].y) solve(1);
	for(int i = 1; i <= n; i++) {
		if(a[i].x || a[i].y) {puts("-1"); return 0;}
	} printf("%d\n", now);
	for(int i = 1; i <= now; i++) printf("%d ", D[i]);
	printf("\n");
	for(int i = 1; i <= n; i++) printf("%s\n", ans[i] + 1);
	return 0;
}


T3
给你一个字符串要求你构造一个字符串长度的树,如果第i个位有1就表示要求割掉一条边之后能分成一个大小为i的连通块,0表示不能分成。


首先无解的情况你可以根据对称性把他判掉。
然后又根据对称性,你只用判小于等于n/2的即可。
从小到大枚举,对于一个i如果有1我们就要保证他有i的连通块,而又不能有多余的连通块,于是你只用在当前的根节点挂一些长度为1的边即可,然后换一个根节点继续挂。


#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
typedef long long LL;
int _min(int x, int y) {return x < y ? x : y;}
int _max(int x, int y) {return x > y ? x : y;}
int read() {
	int s = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
	return s * f;
}

char ss[110000];

int main() {
	scanf("%s", ss + 1);
	int n = strlen(ss + 1);
	if(ss[n] == '1') {puts("-1"); return 0;}
	if(ss[1] == '0') {puts("-1"); return 0;}
	for(int i = 1; i < n; i++) {
		if(ss[i] != ss[n - i]) {puts("-1"); return 0;}
	} int id = 1, now = 1, o = n - 1;
	for(int i = n / 2; i >= 1; i--) {
		if(ss[i] == '1') {
			for(int j = 1; j <= o - i + 1; j++) {
				printf("%d %d\n", now, ++id);
			} o = i - 1; now = id;
		}
	}
	return 0;
}


T4
给你n个点它们每个点到所有点的距离之和,叫你构造出一棵合法的树。


我考试时的想法是从一个距离和最小的点开始挂,因为最小的距离和是重心,但然后发现子节点不知道挂哪里。。。
然后呢,其实你反过来想一想,如果我们从最底层的孩子节点开始挂就方便很多,因为他的tot也是固定的就是1,并且他只有一个父亲,所以就很好做了。


#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
typedef long long LL;
int _min(int x, int y) {return x < y ? x : y;}
int _max(int x, int y) {return x > y ? x : y;}
LL read() {
	LL s = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
	return s * f;
}

struct edge {
	int x, y, next;
} f[110000], e[110000]; int len, last[110000];
struct node {
	LL x; int id;
} a[110000];
LL d[110000], sum;
int tot[110000];

bool cmp(node a, node b) {return a.x < b.x;}

void ins(int x, int y) {
	e[++len].x = x, e[len].y = y;
	e[len].next = last[x], last[x] = len;
}

void dfs(int x, int dis) {
	sum += dis;
	for(int k = last[x]; k; k = e[k].next) {
		int y = e[k].y;
		dfs(y, dis + 1);
	}
}

int main() {
	LL n = read();
	for(LL i = 1; i <= n; i++) a[i].x = read(), a[i].id = i;
	sort(a + 1, a + n + 1, cmp);
	for(LL i = 1; i <= n; i++) d[i] = a[i].x;
	for(LL i = 1; i <= n; i++) tot[i] = 1;
	len = 0;
	for(LL i = n; i > 1; i--) {
		LL u = d[i] - n + 2 * tot[i];
		int fa = lower_bound(d + 1, d + n + 1, u) - d;
		if(d[fa] != u) {puts("-1"); return 0;}
		f[++len].x = fa, f[len].y = i;
		tot[fa] += tot[i];
	} len = 0; for(int i = 1; i < n; i++) ins(f[i].x, f[i].y);
	sum = 0; dfs(1, 0);
	if(sum != d[1]) {puts("-1"); return 0;}
	for(int i = 1; i < n; i++) printf("%d %d\n", a[f[i].x].id, a[f[i].y].id);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/xgc_woker/article/details/82904752