Codeforces Good Bye 2023

A. 2023

正常签到。

void solve() {
	int n, k, ok = 1;
	cin >> n >> k;
	int t = 2023;
	while(n --) {
		int x;
		cin >> x;
		if(t % x) ok = 0;
		t /= x;
	}
	cout << (ok ? "YES\n" : "NO\n");
	if(ok) {
		cout << t << ' ';
		for(int i = 1; i < k; ++ i) cout << '1' << ' ';
		cout << '\n';
	}
}

B. Two Divisors

情况一:\(b \bmod a \neq 0\),答案为 \(lcm(a, b)\)
情况二:\(b \bmod a = 0\),则答案为 \(p \cdot lcm = p \cdot b\)\(p\) 为一个小于 \(a\) 的质数。
由于题目保证 \(a, b\) 是最大两个因子,因此 \(\dfrac{b}{a}\) 为一个小于 \(a\) 的质数。
所以满足题意的一个答案为 \(\dfrac{b}{a} \cdot b\)

void solve() {
	ll a, b;
	scanf("%lld%lld", &a, &b);
	printf("%lld\n", b % a == 0 ? b / a * b : lcm(a, b));
}

C. Training Before the Olympiad

简化题面:在数组中选两个数,将这两个数合并为 \(\lfloor\dfrac{a[i]+a[j]}{2}\rfloor \times 2\),求在最优操作下,最后剩下数是什么。
先手要使最后结果尽可能大,后手要使最后结果尽可能小。

  • 最终答案最大为 $ \sum a[i]$
  • 操作后的整个数一定是偶数。
  • 后手可以通过选取一奇一偶使答案减一。

现在思路就非常清晰了。
情况一:当前数组中奇数的数量为 \(1\),那么先手必选两个偶数,后手必选这个奇数。
情况二:当前数组中奇数的数量为 \(2\),那么先手必选这两个奇数,后手不能使答案变小。
情况三:当前数组中奇数的数量为 \(3\),那么先手必选两个奇数,后手必选剩下的一个奇数。
由此我们可以发现答案与奇数个数 \(\bmod 3\) 有关。

void solve() {
	int n;
	cin >> n;
	vector<ll> a(n + 1, 0), b(n + 1, 0);
	for(int i = 1; i <= n; ++ i) cin >> a[i], b[i] = b[i - 1] + (a[i] % 2),  a[i] += a[i - 1];
	cout << a[1] << ' ';
	for(int i = 2; i <= n; ++ i) {
		cout << a[i] - b[i] / 3 - (b[i] % 3 == 1) << ' ';
	}
	cout << '\n';
}

D. Mathematical Problem

  • 我们要构造的是 \(\lceil \dfrac{n}{2} \rceil\) 位数的平方。
  • \((1 \ldots 3 \ldots)^2\) 一定是 \((1 \ldots 6\ldots9 \ldots)^2\)
  • \((3 \ldots 1 \ldots)^2\) 一定是 \((9 \ldots 6\ldots1 \ldots)^2\)
  • \((14 \ldots)^2)\) 一定是 \((196 \ldots)\)

发现上述三种情况很好地契合本题要求。
现在检验这些情况的数目是否 \(\ge n\)
情况一:以 \(1\) 为首元素枚举后面的位置,共 \(\lfloor \dfrac{n}{2} \rfloor\) 种。
情况一:以 \(3\) 为首元素枚举后面的位置,共 \(\lfloor \dfrac{n}{2} \rfloor\) 种。
情况一:共 \(1\) 种。
加起来共 \(n\) 种,非常完美。

void solve() {
	int n, cnt = 0;
	cin >> n;
	if(n == 1) cout << "1\n";
	else {
		int len = n / 2 + 1;
		for(int i = 0; i < len - 1; ++ i) {
			cout << '1';
			for(int j = 0; j < i; ++ j) cout << '0';
			cout << '6';
			for(int j = 0; j < i; ++ j) cout << '0';
			cout << '9';
			for(int j = 1; j < n - 2 - i * 2; ++ j) cout << '0';
			cout << '\n';
		}	
		for(int i = 0; i < len - 1; ++ i) {
			cout << '9';
			for(int j = 0; j < i; ++ j) cout << '0';
			cout << '6';
			for(int j = 0; j < i; ++ j) cout << '0';
			cout << '1';
			for(int j = 1; j < n - 2 - i * 2; ++ j) cout << '0';
			cout << '\n';
		}
		cout << "196";
		for(int i = 0; i < n - 3; ++ i) cout << '0';
		cout << '\n';
	}
}

E. Happy Life in University

int val[N << 2], tag[N << 2];

void build(int x, int l, int r) {
	val[x] = tag[x] = 0;
	if(l == r) return;
	int mid = l + r >> 1;
	build(x << 1, l, mid), build(x << 1 | 1, mid + 1, r);
}

void pushup(int x) {
	val[x] = max(val[x << 1], val[x << 1 | 1]);
}

void pushdown(int x) {
	tag[x << 1] += tag[x], tag[x << 1 | 1] += tag[x];
	val[x << 1] += tag[x], val[x << 1 | 1] += tag[x];
	tag[x] = 0;
}

void modify(int x, int l, int r, int a, int b, int delta) {
	if(a <= l && r <= b) {
		tag[x] += delta;
		val[x] += delta;
		return;
	}
	pushdown(x);
	int mid = l + r >> 1;
	if(mid >= a) modify(x << 1, l, mid, a, b, delta);
	if(mid < b) modify(x << 1 | 1, mid + 1, r, a, b, delta);
	pushup(x);
}

int query(int x, int l, int r, int a, int b) {
	if(a <= l && r <= b) return val[x];
	pushdown(x);
	int mid = l + r >> 1, ret = 1;
	if(mid >= a) ret = max(ret, query(x << 1, l, mid, a, b));
	if(mid < b) ret = max(ret, query(x << 1 | 1, mid + 1, r, a, b));
	return ret;
}

long long ans;
int n, a[N];
int dfn[N], out[N], timestamp;
int lst[N];				//在x的祖先中离x最近的颜色相同的点
vector<int> G[N], e[N];	//e为在x子树中离x最近的颜色相同的点

void dfs(int x) {	//枚举lca
	dfn[x] = ++ timestamp;
	if(lst[a[x]]) e[lst[a[x]]].push_back(x);
	int tmp = lst[a[x]];
	lst[a[x]] = x;
	for(auto y : G[x]) dfs(y);
	lst[a[x]] = tmp;		//还原last
	out[x] = timestamp;		//[dfn[x], out[x]]为整棵子树对应序列
	modify(1, 1, n, dfn[x], out[x], 1);
	for(auto y : e[x]) modify(1, 1, n, dfn[y], out[y], -1);
	int mx = 1;
	for(auto y : G[x]) {
		int t = query(1, 1, n, dfn[y], out[y]);
		ans = max(ans, 1ll * mx * t);
		mx = max(mx, t);
	}
}

void solve() {
	cin >> n;
	for(int i = 1; i <= n; ++ i) G[i].clear(), e[i].clear();
	for(int i = 2, p; i <= n; ++ i) {
		cin >> p;
		G[p].push_back(i);
	}
	for(int i = 1; i <= n; ++ i) cin >> a[i];
	build(1, 1, n);
	ans = 1, timestamp = 0, dfs(1);
	cout << ans << '\n';
}

F. Group Division

void Tarjan(int x) {
	dfn[x] = low[x] = ++ timestamp;
	int cnt = 0;
	for(int y : G[x]) {
		if(!cs[y]) {
			if(!dfn[y]) {
				Tarjan(y);
				low[x] = min(low[x], low[y]);
				if(low[y] >= dfn[x]) {
					if(x != root || ++ cnt > 1) cut[x] = true;
				}
			}
			else low[x] = min(low[x], dfn[y]);
		}
	}
}

void clear_part() {
	for(int i = 1; i <= n; ++ i) {
		dfn[i] = low[i] = cut[i] = 0;
	}
	timestamp = 0; 
}

void clear_all() {
	for(int i = 1; i <= n; ++ i) {
		dfn[i] = low[i] = cut[i] = cs[i] = 0;
		G[i].clear();
	}
	timestamp = 0;
}

void solve() {
	cin >> n1 >> n2 >> m;
	n = n1 + n2;
	for(int i = 1; i <= m; ++ i) {
		int x, y;
		cin >> x >> y;
		G[x].push_back(y);
		G[y].push_back(x);
	}
	for(int T = 1; T <= n1; ++ T) {
		for(int i = 1; i <= n; ++ i) {
			if(!cs[i]) {
				Tarjan(root = i);
				break;
			}
		}
		for(int i = 1; i <= n; ++ i) {
			if(!cs[i] && !cut[i]) {
				bool ok = false;
				for(int y : G[i]) ok |= cs[y];
				if(ok || T == 1) {
					cs[i] = 1;
					break;
				}
			}
		}
		clear_part();
	}
	for(int i = 1; i <= n; ++ i) if(cs[i]) cout << i << ' '; cout << '\n';
	for(int i = 1; i <= n; ++ i) if(!cs[i]) cout << i << ' '; cout << '\n';
	clear_all();
}
posted @ 2024-01-03 19:45  Lu_xZ  阅读(9)  评论(0编辑  收藏  举报