Codeforces Round #835 (Div. 4)题解

本文分享了一次 CF Div4 比赛的经历及题解,包括 A 到 G 题目的代码实现,涉及贪心算法、二分搜索、图论等内容,并对 F 和 G 题进行了详细解析。

补完一套div4,此图为证

第一次补完一套完整的div,纪念一下

提交记录

提交记录

说明

题目链接
一共7个题,做出前5题,排到接近四千名了。前5题就是模拟或者像前缀和后缀和之类的简单题,没什么好说的。比较难想的是F,好想但是细节多难调的是压轴题G。

A题 Medium Number

// cf div4.cpp : 定义控制台应用程序的入口点。
//
//#include "stdafx.h"
#include<bits/stdc++.h>
using namespace std;
int main()
{
	int t; cin >> t;
	while (t--) {
		int a, b, c;
		cin >> a >> b >> c;
		cout << a + b+c - min(a, min(b, c)) - max(a, max(b, c)) << endl;
	}
	//system("pause");
    return 0;
}

B题 Atilla’s Favorite Problem

// cf div4.cpp : 定义控制台应用程序的入口点。
//
//#include "stdafx.h"
#include<bits/stdc++.h>
using namespace std;
int main()
{
	int t; cin >> t;
	while (t--) {
		int n; cin >> n;
		string s; cin >> s;
		int maxn = 'a' - '0';
		for (int i = 0; i < n; i++) {
			int x = s[i] - '0';
			maxn = max(maxn, x);
		}
		cout << maxn - 'a'+'0' + 1 << endl;
	}
	//system("pause");
    return 0;
}

C题 Advantage

#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 5;
int s[maxn];
int main()
{
	int t; cin >> t;
	while (t--) {
		int n; cin >> n;
		int maxx1 = -1e9, idmax1 = 0, maxx2 = -1e9, idmax2 = 0;
		for (int i = 1; i <= n; i++) {
			cin >> s[i];
			if (s[i] > maxx1)maxx1 = s[i], idmax1 = i;
		}
		for (int i = 1; i <= n; i++) {
			if (i == idmax1)continue;
			if (s[i] > maxx2)maxx2 = s[i], idmax2 = i;
		}
		for (int i = 1; i <= n; i++) {
			if (i != idmax1)cout << s[i] - maxx1;
			else cout << s[i] - maxx2;
			if (i != n)cout << " ";
		}
		cout << endl;
	}
	//system("pause");
    return 0;
}

D题 Challenging Valleys

找最低的位置判两侧单调性。

// cf div4.cpp : 定义控制台应用程序的入口点。
//
//#include "stdafx.h"
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 5;
int a[maxn];
int main()
{
	int t; cin >> t;
	while (t--) {
		int n; cin >> n;
		bool flag = false;
		for (int i = 0; i < n; i++) {
			cin >> a[i];
		}
		int l = 1, r = 1;
		bool pd1 = true, pd2 = true;
		for (int i = 0; i<n-1; i++) {
			if (a[i+1] < a[i])pd1=false;
		}
		for (int i = 0; i<n-1; i++) {
			if (a[i + 1] > a[i])pd2 = false;
		}
		if (pd1 == true || pd2 == true)flag = true;
		int minpos = -1, minn = 1e9;
		for (int i = 0; i < n; i++) {
			if (a[i] < minn)minpos = i, minn = a[i];
		}
		bool pd3 = true, pd4 = true;
		for (int i = minpos; i < n-1; i++) {
			if (a[i+1] < a[i])pd3 = false;
		}
		for (int i = minpos; i >= 1; i--) {
			if (a[i-1] < a[i])pd4 = false;
		}
		if (pd3 == true && pd4 == true)flag = true;
		if (flag == true)puts("YES");
		else puts("NO");
	}
//	system("pause");
    return 0;
}

E题 Binary Inversions

分别求一遍前缀和和后缀和。

// cf div4.cpp : 定义控制台应用程序的入口点。
//
//#include "stdafx.h"
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 5;
int a[maxn];
int cnt0f1[maxn], cnt0b0[maxn], cnt1f1[maxn], cnt1b0[maxn];
int cnt0[maxn], cnt1[maxn];
int main()
{
	int t; cin >> t;
	while (t--) {
		memset(cnt0, 0, sizeof(cnt0));
		memset(cnt1, 0, sizeof(cnt1));
		int n; cin >> n;
		for (int i = 0; i < n; i++) {
			cin >> a[i];
		}
		for (int i = 0; i < n-1; i++) {
			if (a[i] == 1) {
				cnt1[i+1]++;
			}
		}
		for (int i = 1; i < n; i++) {
			cnt1[i] += cnt1[i - 1];
		}
		for (int i = n - 1; i > 0; i--) {
			if (a[i] == 0) {
				cnt0[i - 1]++;
			}
		}
		for (int i = n - 1; i > 0; i--) {
			cnt0[i - 1] += cnt0[i];
		}
		//for (int i = 0; i < n; i++)cout << cnt0[i] << " ";
		//cout << endl;
		//for (int i = 0; i < n; i++)cout << cnt1[i] << " ";
		//cout << endl;
		long long ini = 0;
		for (int i = 0; i < n; i++) {
			if (a[i] == 1) {
				ini += cnt0[i];
			}
		}
		int maxx = -1e9;
		for (int i = 0; i < n; i++) {
			int x = cnt0[i];
			int y = cnt1[i];
			if (a[i] == 0) {
				maxx = max(maxx, x - y);
			}
			else {
				maxx = max(maxx, y - x);
			}
		}
		maxx = max(maxx, 0);
		cout << ini + maxx << endl;
	}
	//system("pause");
    return 0;
}

F题 Quests

按照贪心的思路,先排序,然后二分答案。

// 11.21-cf-div4-F.cpp : 定义控制台应用程序的入口点。
//
//#include "stdafx.h"
#include<bits/stdc++.h>
using namespace std;
int n, d;
long long c;
const int maxn = 2e5 + 5;
int a[maxn];
int main()
{
	int t; cin >> t;
	while (t--) {
		cin >> n >> c >> d;
		for (int i = 1; i <= n; i++)cin >> a[i];
		sort(a + 1, a + 1 + n, greater<int>());
		if ((long long)a[1] * (long long)d < c) {
			puts("Impossible"); continue;
		}
		long long sum = 0;
		for (int i = 1; i <= min(n, d); i++)sum += a[i];
		if (sum >= c) {
			puts("Infinity"); continue;
		}
		int left = 1, right = d, mid, k;
		while (left <= right) {
			mid = (left + right) >> 1;
			long long all = 0;
			for (int i = 1; i <= min(mid, n); i++)all += a[i];
			int res = d%mid;
			int re = d / mid;
			all *= re;
			for (int i = 1; i <= min(res, n); i++)all += a[i];
			if (all >= c) {
				k = mid;
				left = mid + 1;
			}
			else if (all < c)right = mid - 1;
		}
		k--;
		cout << k << endl;
	}
	//system("pause");
    return 0;
}

G题 SlavicG’s Favorite Problem

后来补这个题的时候我是用链式前向星写的,中间有些细节调了很久。

// 11.21-cf-div4-G.cpp : 定义控制台应用程序的入口点。
//
//#include "stdafx.h"
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 5;//双向图翻倍
struct node {
	int next;
	int to;
	int w;
}edge[maxn];
int cnt, head[maxn], n, a, b;
map<int, bool> mp;
void dfs_a(int u, int fa, int cur) {
	for (int i = head[u]; i != -1; i = edge[i].next) {
		if (edge[i].to == b)continue;//a不能直接到b
		if (edge[i].to != fa) {
			mp[cur^edge[i].w] = true;//必须异或别人才能记,一开始是0不能记
			dfs_a(edge[i].to, u, cur^edge[i].w);
		}
	}
}
bool flag;
void dfs_b(int u, int fa, int cur) {//有从某位置传送到a再到b的可能性
	for (int i = head[u]; i != -1; i = edge[i].next) {
		if (edge[i].to != fa) {
			if (mp[cur^edge[i].w] == true) {
				flag = true; return;
			}
			dfs_b(edge[i].to, u, cur^edge[i].w);
		}
	}
}
void add(int u, int v, int w) {
	edge[cnt].next = head[u];
	head[u] = cnt;
	edge[cnt].w = w;
	edge[cnt].to = v;
	cnt++;
}
int main()
{
	int t; cin >> t;
	while (t--) {
		mp.clear();
        memset(head, -1, sizeof(head));
		cin >> n >> a >> b;
		cnt = 0;
		for (int i = 1; i < n; i++) {//只有n-1个输入,不是0到n-1,是1到n-1
			int u, v, w;
			cin >> u >> v >> w;
			add(u, v, w);
			add(v, u, w);
		}
		//由于权值不会是0,不用特判a直接到b
		dfs_a(a, -1, 0);
		flag = false;
		mp[0] = true;//若从a直接可以到b,那dfs_b有0出现
		dfs_b(b, -1, 0);//若dfs_a中没有0,此时0也应该有
		if (flag)puts("YES");
		else puts("NO");
	}
	//system("pause");
    return 0;
}

小结

需要强化的知识点:贪心、二分、建图、树上遍历

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

keguaiguai

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值