Osijek Competitive Programming Camp, Fall 2023. Day 6: Estonian Contest (The 2nd Universal Cup. Stag

Osijek Competitive Programming Camp, Fall 2023. Day 6: Estonian Contest (The 2nd Universal Cup. Stage 19: Estonia)

 回家好久没做题了,写个题解慢慢补吧,可能会补个8题左右

目录

Problem E. Freshman’s Dream

Problem I. Rebellious Edge

G. LCA Counting

C. Yet Another Balanced Coloring Problem


Problem E. Freshman’s Dream

易知(a+b)=a^(b+n)

如果奇数的话a,b不管怎么取奇偶都是相反的,所以不可能

令a+b=2^{60},a=\frac{n}{2},b=2^{60}-\frac{n}{2}

2^{60}=\frac{n}{2}(2^{60}-\frac{n}{2}+n)

2^{60}=\frac{n}{2}(2^{60}+\frac{n}{2})

因为\frac{n}{2}=n>>1

所以n/2小于2^60

所以成立

#define int long long
#define PII pair<int,int>
const int inf = 0x3f3f3f3f3f3f3f3f, N = 1e5 + 5, mod = 1e9 + 7;
signed main()
{
	ios_base::sync_with_stdio(0); cin.tie(0), cout.tie(0);
	int T;
	cin >> T;
	while (T--)
	{
		int n;
		cin >> n;
		if (n & 1) {
			cout << -1 << '\n';
		}
		else {
			cout << n / 2 << ' ' << (1ll << 60) - n / 2 << '\n';
		}
	}
}
Problem I. Rebellious Edge

由题目可知

 All edges, except for exactly one, are directed from the vertex with the smaller index to the vertex with the bigger index.

除了一条边往小的走其余的都是往大的方向走

如果不考虑往回走的边的话,那么转移是很容易的,直接从左往右 每个点都选指向他的最小的边就行了

如果我们考虑往回走的情况

就如同他样例给的那样

如果我们每个点都选指向他的最小的边的话,会是如下样子

这时候就可能会出现自环

我们消除自环的话有两种方法

第一种是不选回来的边,让图形变成我上面所说的那样 

如果不考虑往回走的边的话,那么转移是很容易的,直接从左往右 每个点都选指向他的最小的边就行了

另外一种是改变连接方式,就是每个边就不一定是选最小的了,我们要保证像上面那样5和1必须要有连接,这时候我们可以建立反相变,去从5开始跑一遍最短路,从而使其中部分点的连接方式进行更改,从而使5和1有连接

#define int long long
#define PII pair<int,int>
const int inf = 0x3f3f3f3f3f3f3f3f, N = 2e5 + 5, mod = 1e9 + 7;
vector<PII>q[N];
signed main()
{
	ios_base::sync_with_stdio(0); cin.tie(0), cout.tie(0);
	int T;
	cin >> T;
	while (T--)
	{
		int n, m;
		cin >> n >> m;
		for (int i = 1; i <= n; i++) {
			q[i].clear();
		}
		vector<int>dis(n + 1, 2e9);
		vector<int>vis(n + 1);
		int l, r;
		for (int i = 1; i <= m; i++)
		{
			int u, v, w;
			cin >> u >> v >> w;
			q[v].push_back({ u,w });//反向边
			if (u > v)
				l = v, r = u;//对特殊的两点进行记录
		}
		int ans = 0;
		for (int i = 2; i <= n; i++) {
			int mi = 2e9;
			for (auto w : q[i]) {
				mi = min(mi, w.second);
			}
			ans += mi;//都选最小的
		}
		if (l == 1) {
			cout << ans << '\n';
			continue;
		}
		int val = 2e9;
		{
			int mi = 2e9;
			for (auto w : q[l])
				mi = min(mi, w.second);
			for (auto w : q[l])
				if (w.first < l)//如果不选反向边的话
					val = min(val, w.second - mi);
		}
		dis[r] = 0;
		priority_queue<PII>que;
		que.push({ 0,r });
		while (que.size()) {
			auto t = que.top();
			que.pop();
			int d = t.first, cur = t.second;
			d = -d;
			if (cur == 1) {
				val = min(val, d);//使1和r进行连接需要修改的距离
				break;
			}
			if (vis[cur]) continue;
			vis[cur] = 1;
			int mi = 2e9;
			for (auto w : q[cur])
				mi = min(mi, w.second);
			for (auto w : q[cur]) {
				if (dis[w.first] > d+(w.second - mi)) {//因为原本我们都是选最小值,现在需要修改的话就用当前值减最小值
					dis[w.first] = d + (w.second - mi);
					que.push({ - dis[w.first],w.first });
				}
			}
		}
		cout << ans + val << "\n";//只选最小值+需要修改的值
	}
}
G. LCA Counting

看代码好懂一点,不知道怎么去表达

const int inf = 0x3f3f3f3f3f3f3f3f, N = 2e5 + 5, mod = 1e9 + 7;
vector<int>q[N];
int sz[N];
int cnt[N];
priority_queue<int>pq[N];
void dfs(int u)
{
	if (q[u].empty()) {
		sz[u]++;
		pq[u].push(1);
		return;
	}
	PII max1 = { 0,-1 }, max2 = { 0,-1 };
	for (int v : q[u]) {
		dfs(v);
		sz[u] += sz[v];
		int d = pq[v].top();
		if (make_pair(d, v) > max1) max2 = max1, max1 = { d,v };
		else if (make_pair(d, v) > max2) max2 = { d,v };
	}
	pq[u].push(max1.first + max2.first);
	if (max1.second != -1) {
		int v = max1.second;
		pq[v].pop();
	}
	if (max2.second != -1) {
		int v = max2.second;
		pq[v].pop();
	}
	for (int v : q[u]) {
		if ((int)pq[u].size() < (int)pq[v].size()) pq[u].swap(pq[v]);
		while (!pq[v].empty()) {
			pq[u].push(pq[v].top());
			pq[v].pop();
		}
	}
}
signed main()
{
	ios_base::sync_with_stdio(0); cin.tie(0), cout.tie(0);
	int n;
	cin >> n;
	for (int i = 2; i <= n; i++) {
		int p;
		cin >> p;
		q[p].push_back(i);
	}
	dfs(1);
	int cur = 1;
	while (!pq[1].empty()) {
		cnt[cur]=1;
		cur += pq[1].top();
		pq[1].pop();
	}
	for (int i = 1; i <= sz[1]; i++) {
		if (cnt[i] == 1) {
			cnt[i] += cnt[i - 1];
		}
		else {
			cnt[i] += cnt[i - 1] + 2;
		}
		cout << cnt[i] << ' ';
	}
	cout << '\n';
}
C. Yet Another Balanced Coloring Problem

懒得写题解了,感觉还不如看代码,题目的题解也看不懂说什么

#define int long long//__int128 2^127-1(GCC)
#define PII pair<int,int>
const int inf = 0x3f3f3f3f3f3f3f3f, N = 1e5 + 5, mod = 1e9 + 7;
signed main()
{
	ios_base::sync_with_stdio(0); cin.tie(0), cout.tie(0);
	int T;
	cin >> T;
	while (T--)
	{
		int n, m;
		cin >> n >> m;
		vector<vector<PII>>adj(n + m + 1);
		vector<vector<int>>g1(n + 1);
		vector<vector<int>>g2(m + 1);
 
		for (int i = 1; i < n; i++)
		{
			int x;
			cin >> x;
			g1[x].push_back(i);
		}
		for (int i = 1; i < m; i++)
		{
			int x;
			cin >> x;
			g2[x].push_back(i);
		}
		int k = 0;
		int cur = 0;
		auto dfs = [&](auto self, int u, int f, int d, const vector<vector<int>>& G)->void {
			for (auto v : G[u]) {
				self(self, v, u, d, G);
			}
			int x = 0;
			if (G[u].size() == 0) x = -d, k++;
			if ((G[u].size() == 0 || adj[u + x + d].size() % 2) && f) {
				adj[f + d].push_back({ u + x + d, cur });
				adj[u + x + d].push_back({ f + d, cur });
				cur++;
			}
		};
		dfs(dfs, n, 0, 0, g1);
		dfs(dfs, m, 0, n, g2);
		k /= 2;
		vector<int>vis(cur), que;
		auto dfs2 = [&](auto self, int u)->void {
			for (auto w : adj[u]) {
				int v = w.first;
				int idx = w.second;
				if (vis[idx]) continue;
				vis[idx] = 1;
				self(self, v);
			}
			que.push_back(u);
		};
		for (int i = k + 1; i <= n + m; i++) {
			if (adj[i].size() % 2)
				dfs2(dfs2, i);
		}
		for (int i = k + 1; i <= n + m; i++) {
			dfs2(dfs2, i);
		}
		string ans(k, 'R');
		char col = 'R';
 
		for (int x : que) {
			if (x <= k) {
				ans[x - 1] = col;
				col = 'R' + 'B' - col;
			}
		}
		cout << ans << '\n';
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值