1. 程式人生 > >AtCoder Regular Contest 103 構造專場?

AtCoder Regular Contest 103 構造專場?

這場比賽除了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;
}