一万一参赛,赛时排名 151

A. Meaning Mean

简单贪心题。显然,排在越后面的数,除以 2 的次数越少。

因此贪心地从小到大计算结果即为答案。

#include<bits/stdc++.h>
using namespace std;
const int N = 55;
int T, n, a[N];

int main() {
	scanf("%d", &T);
	while(T --) {
		scanf("%d", &n);
		for(int i = 1; i <= n; i ++)
			scanf("%d", &a[i]);
		sort(a + 1, a + n + 1);
		int ans = a[1];
		for(int i = 2; i <= n; i ++) {
			ans = (ans + a[i]) / 2;
		}
		printf("%d\n", ans);
	}
	return 0;
}

B. Maximize Mex

简单模拟题。显然,若一个数在原序列中没有出现,那它只能由更小的数通过加法得到。

这个更小的数需要满足它本身是多出来的,且它和当前缺少的数相差 k * x 。

因此从小到大枚举可能的 Mex ,尽量补全缺失的数即可。

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int T, n, x, a[N], cnt[N];

int main() {
	scanf("%d", &T);
	while(T --) {
		scanf("%d%d", &n, &x);
		for(int i = 1; i <= n; i ++)
			scanf("%d", &a[i]);
		sort(a + 1, a + n + 1);
		for(int i = 0; i <= n; i ++) cnt[i] = 0;
		for(int i = 0, j = 1; i <= n; i ++) {
			while(j <= n && a[j] <= i) cnt[a[j] % x] ++, j ++;
			if(cnt[i % x]) cnt[i % x] --;
			else {
				printf("%d\n", i);
				break;
			}
		}
	}
	return 0;
}

C2. Adjust The Presentation

一个结论, b 数组中每个数第一次出现的先后次序必须满足 a 数组中的先后次序。考虑对 b 数组做一个从 a 数组来的映射。

问题转化为 b 数组各个数第一次出现位置是否按照大小升序排列,每次单点修改。

可以维护下降断点的数量,每次修改只会改变 O(1) 个断点的状态。断点为 0 表示当前 b 数组符合条件。

#include<bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII;
const int N = 2e5 + 10;
int T, n, m, q, a[N], pos[N], fst[N];
priority_queue<int, vector<int>, greater<int> > q1[N], q2[N];
bool is[N];

int main() {
	scanf("%d", &T);
	while(T --) {
		scanf("%d%d%d", &n, &m, &q);
		for(int i = 1; i <= n; i ++){
			while(q1[i].size()) q1[i].pop();
			while(q2[i].size()) q2[i].pop();
			is[i] = false;
		}
		for(int i = 1; i <= n; i ++)
			scanf("%d", &a[i]), pos[a[i]] = i, q1[i].push(m + 1);
		for(int i = 1; i <= m; i ++)
			scanf("%d", &a[i]), a[i] = pos[a[i]];
		for(int i = 1; i <= m; i ++)
			q1[a[i]].push(i);
		for(int i = 1; i <= n; i ++)
			fst[i] = q1[i].top();
		int cnt = 0;
		for(int i = 1; i < n; i ++)
			if(fst[i] > fst[i + 1]) is[i] = true, cnt ++;
		puts(!cnt ? "YA" : "TIDAK");
		for(int i = 1, x, t; i <= q; i ++) {
			scanf("%d%d", &x, &t);
			t = pos[t];
			q2[a[x]].push(x);
			while(q2[a[x]].size() && q1[a[x]].top() == q2[a[x]].top()) q1[a[x]].pop(), q2[a[x]].pop();
			fst[a[x]] = q1[a[x]].top();
			if(a[x] < n) {
				if(fst[a[x]] <= fst[a[x] + 1] && is[a[x]]) is[a[x]] = false, cnt --;
				if(fst[a[x]] > fst[a[x] + 1] && !is[a[x]]) is[a[x]] = true, cnt ++;
			} 
			if(a[x] > 1) {
				if(fst[a[x]] >= fst[a[x] - 1] && is[a[x] - 1]) is[a[x] - 1] = false, cnt --;
				if(fst[a[x]] < fst[a[x] - 1] && !is[a[x] - 1]) is[a[x] - 1] = true, cnt ++;
			}
			a[x] = t;
			q1[t].push(x);
			while(q2[t].size() && q1[t].top() == q2[t].top()) q1[t].pop(), q2[t].pop();
			fst[t] = q1[t].top();
			if(t < n) {
				if(fst[t] <= fst[t + 1] && is[t]) is[t] = false, cnt --;
				if(fst[t] > fst[t + 1] && !is[t]) is[t] = true, cnt ++;
			} 
			if(a[x] > 1) {
				if(fst[t] >= fst[t - 1] && is[t - 1]) is[t - 1] = false, cnt --;
				if(fst[t] < fst[t - 1] && !is[t - 1]) is[t - 1] = true, cnt ++;
			}
			puts(!cnt ? "YA" : "TIDAK");
		}
	}
	return 0;
}

E1. Digital Village (Easy Version)

先 floyed 求出每两个点之间路径最大边权的最小值。

随后贪心地加入当前能使答案最小的点即可。

#include<bits/stdc++.h>
using namespace std;
const int N = 405;
int T, n, m, p, dis[N][N], d[N], s[N];
bool vis[N];

int main() {
	scanf("%d", &T);
	while(T --) {
		scanf("%d%d%d", &n, &m, &p);
		for(int i = 1; i <= n; i ++)
			d[i] = 2e9, vis[i] = false;
		for(int i = 1; i <= n; i ++)
			for(int j = 1; j <= n; j ++)
				dis[i][j] = 2e9;
		for(int i = 1; i <= n; i ++) dis[i][i] = 0;
		for(int i = 1; i <= p; i ++)
			scanf("%d", &s[i]);
		for(int i = 1, u, v, w; i <= m; i ++) {
			scanf("%d%d%d", &u, &v, &w);
			dis[u][v] = dis[v][u] = min(dis[u][v], w);
		}
		for(int k = 1; k <= n; k ++)
			for(int i = 1; i <= n; i ++)
				for(int j = 1; j <= n; j ++)
					if(i != j && j != k && k != i)
						dis[i][j] = min(dis[i][j], max(dis[i][k], dis[k][j]));
		
		long long ans = 1e18;
		for(int i = 1; i <= n; i ++) {
			int id = 0;
			for(int j = 1; j <= n; j ++) {
				if(vis[j]) continue;
				long long res = 0;
				for(int k = 1; k <= p; k ++)
					res += min(d[s[k]], dis[j][s[k]]);
				if(res < ans) ans = res, id = j;
			}
			printf("%lld ", ans);
			vis[id] = true;
			for(int j = 1; j <= p; j ++)
				d[s[j]] = min(d[s[j]], dis[id][s[j]]);
		}
		puts("");
	}
	return 0;
}