Codeforces Round #790 (Div.4) A-H2题解

原题链接:

https://codeforces.com/contest/1676

A. Lucky?

题意:给定长度为6由数字组成的字符串问前三个数字的和是否等后三个数字的和。

题解:直接相加比较即可。

#include<bits/stdc++.h>
typedef long long int ll;
using namespace std;
const int N = 2e5 + 10;
void solve()
{
	string s;
	cin >> s;
	if (s[0] + s[1] + s[2] == s[3] + s[4] + s[5])
		cout << "YES" << endl;
	else
		cout << "NO" << endl;
}
int main()
{
	ll t;
	cin >> t;
	while (t--)
	{
		solve();
	}
	return 0;
}

B. Equal Candies

题意:每个盒子有一定数量的糖果,问让每个盒子糖果数量一样要吃掉多少糖果。

题解:很明显每个盒子糖果数量是由糖果数最少的决定的,只要记录一下最小值计算一下即可。

#include<bits/stdc++.h>
typedef long long int ll;
using namespace std;
const int N = 2e5 + 10;
ll n, a[N];
void solve()
{
	ll ans = 0, mi = INT_MAX;
	cin >> n;
	for (int i = 1; i <= n; i++) cin >> a[i], mi = min(mi, a[i]), ans += a[i];
	//ans记录所有糖果的数量
	cout << ans - mi * n << endl;
}
int main()
{
	ll t;
	cin >> t;
	while (t--)
	{
		solve();
	}
	return 0;
}

C. Most Similar Words

题意:给定一系列长度为n的字符串,找到difference最小的一对字符串,输出它们的difference值。

difference值为每个字符的差距值,如a和b的差距值为1。

题解:范围不大,暴力枚举每一对字符串,记录差距值最小即可。

#include<bits/stdc++.h>
typedef long long int ll;
using namespace std;
const int N = 2e5 + 10;
ll n;
string str[N];
void solve()
{
	ll res, k, mi = INT_MAX;
	cin >> n >> k;
	for (int i = 1; i <= n; i++) cin >> str[i];
	for (int i = 1; i <= n; i++)
	{
		for (int j = i + 1; j <= n; j++)
		{
			res = 0;
			for (int x = 0; x < k; x++)
			{
				res += abs(str[i][x] - str[j][x]);
			}
			mi = min(mi, res);
		}
	}
	cout << mi << endl;
}
int main()
{
	ll t;
	cin >> t;
	while (t--)
	{
		solve();
	}
	return 0;
}

D. X-Sum

题意:给定一个矩阵,每个位置有一个值,你可以在某个位置(x,y)放置一个棋子,棋子取得的值为四个斜对角方向的所有值(如图),问这个值最大是多少。

image

题解:没什么好思考的,直接暴力枚举

#include<bits/stdc++.h>
typedef long long int ll;
using namespace std;
const int N = 2e5 + 10;
ll n, m, mp[500][500];
void solve()
{
	ll ans = 0, k, res;
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= m; j++)
		{
			cin >> mp[i][j];
		}
	}
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= m; j++)
		{
			res = mp[i][j], k = 1;
			while (i - k >= 1 && j - k >= 1)
			{
				res += mp[i - k][j - k];
				k++;
			}
			k = 1;
			while (i + k <= n && j + k <= m)
			{
				res += mp[i + k][j + k];
				k++;
			}
			k = 1;
			while (i + k <= n && j - k >= 1)
			{
				res += mp[i + k][j - k];
				k++;
			}
			k = 1;
			while (i - k >= 1 && j + k <= m)
			{
				res += mp[i - k][j + k];
				k++;
			}
			ans = max(ans, res);
		}
	}
	cout << ans << endl;
}
int main()
{
	ll t;
	cin >> t;
	while (t--)
	{
		solve();
	}
	return 0;
}

E. Eating Queries

题意:每个糖果有个甜度,多组询问达到k个甜度至少要吃多少个糖果。

题解:对甜度降序排序,求一下前缀和,然后二分即可。

#include<bits/stdc++.h>
typedef long long int ll;
using namespace std;
const int N = 2e5 + 10;
bool cmp(ll x, ll y) { return x > y; }
ll n, m, a[N], sum[N];
void solve()
{
	ll k;
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i];
	}
	sort(a + 1, a + n + 1, cmp);
	for (int i = 1; i <= n; i++)
	{
		sum[i] = sum[i - 1] + a[i];
	}
	while (m--)
	{
		cin >> k;
		if (sum[n] >= k)
			cout << lower_bound(sum + 1, sum + n + 1, k) - sum << endl;
		else
			cout << -1 << endl;
	}
}
int main()
{
	ll t;
	cin >> t;
	while (t--)
	{
		solve();
	}
	return 0;
}

F. Longest Strike

题意:给定一个数组,求最长的连续的片段且每个数的个数大于k。

题解:map记录个数,去重后循环一遍,按连续片段枚举,记录答案即可,留意一下细节。

#include<bits/stdc++.h>
typedef long long int ll;
using namespace std;
const int N = 2e5 + 10;
ll n, a[N];
void solve()
{
	pair<ll, ll> cnt;
	map<ll, ll> p;
	set<ll> st;
	ll k;
	cin >> n >> k;
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i];
		p[a[i]] ++;
	}
	sort(a + 1, a + n + 1);
	int r = unique(a + 1, a + n + 1) - a;
	cnt.first = -1;
	for (int i = 1; i < r; i++)
	{
		if (st.count(a[i]) || p[a[i]] < k) continue;
		int j = 0;
		while(p[a[i] + j] >= k)
		{
			st.insert(a[i] + j);
			j++;
		}
		if (j > cnt.second)
		{
			cnt.first = i;
			cnt.second = j;
		}
	}
	if (cnt.first != -1)
	{
		cout << a[cnt.first] << " " << a[cnt.first] + cnt.second - 1 << endl;
	}
	else
	{
		cout << -1 << endl;
	}
}
int main()
{
	ll t;
	cin >> t;
	while (t--)
	{
		solve();
	}
	return 0;
}

G. White-Black Balanced Subtrees

题意:给定一个树,每个节点是黑色或者白色,问有多少个子树黑色节点数量和白色节点数量一样。

题解:拓扑排序,根据入度从下往上dfs,每次判断一下黑色节点的数量和白色节点的数量是否相同即可。

#include<bits/stdc++.h>
typedef long long int ll;
using namespace std;
const int N = 2e5 + 10;
ll n, m, rd[4010], f[4010];
string s;
vector<ll> v[4010];
pair<ll, ll> c[4010];
void dfs()
{
	for (int p = 1; p <= n; p++)
	{
		for (int i = 1; i <= n; i++)
		{
			if (rd[i] == 0 && f[i] == 0)
			{
				f[i] = 1;
				if (c[i].first == c[i].second)
				{
					m++;//存储答案
				}
				//更新父节点的值
				for (int j = 0; j < v[i].size(); j++)
				{
					c[v[i][j]].first += c[i].first;
					c[v[i][j]].second += c[i].second;
					rd[v[i][j]] --;
				}
			}
		}
	}
}
void solve()
{
	memset(rd, 0, sizeof rd);
	memset(f, 0, sizeof f);
	memset(c, 0, sizeof c);
	m = 0;
	ll ans = 0, k;
	cin >> n;
	for (int i = 1; i <= n; i++) v[i].clear();
	for (int i = 1; i < n; i++)
	{
		cin >> k;
		v[i + 1].push_back(k);
		rd[k] ++;
	}
	cin >> s;
	for (int i = 0; i < s.size(); i++)
	{
		if (s[i] == 'W')
		{
			c[i + 1].first++;
		}
		else
		{
			c[i + 1].second++;
		}
	}
	dfs();
	cout << m << endl;
}
int main()
{
	ll t;
	cin >> t;
	while (t--)
	{
		solve();
	}
	return 0;
}

H1. Maximum Crossings (Easy Version)

题意:从1到n每个点都与下面另一个点存在一条边,求交点个数。

image

题解:考虑一下存在交点的情况。对于两条线段(x1, y1)、(x2, y2),存在交点的情况即x2 >= x1 && y2 <= y1 或者 x2 <= x1 && y2 >= y1。对于每条线段x是单调递增的,即x[n] > x[n - 1]恒成立,那么对于每一个x[n]只需要判断前面有多少线段满足y[n] <= y[n - 1]即可。H1范围比较小可以直接暴力来做。我是每次枚举线段时按y值排序,这样就能二分直接找到满足条件的个数,想着一次性把H1和H2过了,但是还是过不了H2,白搞。

#include<bits/stdc++.h>
typedef long long int ll;
using namespace std;
const int N = 2e5 + 10;
ll n;
pair<ll, ll> a[200010];
void solve()
{
	vector<ll> v;
	ll ans = 0, pos;
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i].second;
		a[i].first = i;
	}
	for (int i = 1; i <= n; i++)
	{
		if (i != 1)
		{
			pos = lower_bound(v.begin(), v.end(), a[i].second) - v.begin();
			if (pos < v.size() && v[pos] >= a[i].second) ans += v.size() - pos;
		}
		v.push_back(a[i].second);
		sort(v.begin(), v.end());
	}
	cout << ans << endl;
}
int main()
{
	ll t;
	cin >> t;
	while (t--)
	{
		solve();
	}
	return 0;
}

H2. Maximum Crossings (Hard Version)

题意:从1到n每个点都与下面另一个点存在一条边,求交点个数。(n的范围从上题的1e3变成了2e5)

题解:其实把问题转化一下就简单了,我们先按y值排序后就是求前面有多少个x的值小于当前这个x,等价于求逆序对的问题,直接套求逆序对lowbit版本,就搞定了。

#include<bits/stdc++.h>
typedef long long int ll;
using namespace std;
const int N = 2e5 + 10;
bool cmp1(pair<ll, ll> x, pair<ll, ll> y) { return (x.second != y.second)? x.second < y.second : x.first > y.first; }
#define lowbit(x) x & -x
ll n, m, c[N];
pair<ll, ll> a[200010];
void modify(ll x, ll d) {
	for (int i = x; i <= n; i += lowbit(i)) c[i] += d;
}
ll getsum(ll x) {
	ll sum = 0;
	for (int i = x; i >= 1; i -= lowbit(i)) sum += c[i];
	return sum;
}
void solve()
{
	memset(c, 0, sizeof c);
	vector<ll> v;
	ll ans = 0;
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i].second;
		a[i].first = i;
	}
	sort(a + 1, a + n + 1, cmp1);
	for (int i = 1; i <= n; i++)
	{
		v.push_back(a[i].first);
	}
	for (int i = 0; i < v.size(); i++) {
		ans += getsum(n) - getsum(v[i]);
		modify(v[i], 1);
	}
	cout << ans << endl;
}
int main()
{
	std::ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	ll t;
	cin >> t;
	while (t--)
	{
		solve();
	}
	return 0;
}
posted @ 2022-11-23 15:51  wockcow  阅读(60)  评论(0编辑  收藏  举报