Codeforces Global Round 16 题解(A~D2)

比赛场次链接:点击这里传送

官方题解链接:点击这里传送


Codeforces 1566A 题目链接:点击这里传送

在这里插入图片描述
题意:
给出一个组序列所有数的个数和他们的和,要求你构造出一个非递减序列,使得这个序列的中位数尽可能大并输出这个中位数。
思路:
中位数前面的数全设为0,后面的数取平均值(向下取整)。

#include<bits/stdc++.h>
using namespace std;
int t, n, sum;
//7 3
//8 3
int main()
{
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	cin >> t;
	while (t--)
	{
		cin >> n >> sum;
		int a = (n - 1) / 2;//被删掉的数
		a = n - a;
		cout << sum / a << endl;
	}

	return 0;
}

Codeforces 1566B 题目链接:点击这里传送

在这里插入图片描述
题意:
给出一个只包含01的字符串,要求你将他分为若干个子串,使得每个子串中最小的未出现的数的和最小。
思路:
结论一:这个和最大为2,因为整个字符串只由0和1组成
如果是若干个连续的1组成的子串,那么他产生的贡献为0。
如果是若干个连续的0组成的子串,那么他产生的贡献为1。
如果01混杂,那么产生的贡献为2
结论二:要把0和1分开来,连续0串的个数即为sum,且ans=min(2,sum)

#include<bits/stdc++.h>
using namespace std;
string s;
int t;
int ans;
int sum_0;
int main()
{
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	cin >> t;
	while (t--)
	{
		cin >> s;
		sum_0 = 0;
		int i = 0;
		while (i < s.length())
		{
			if (s[i] == '1') i++;
			else
			{
				int j = i;
				while (s[j + 1] == '0' && j < s.length()) j++;
				sum_0++;
				i = j+1;
			}
		}
		if (sum_0 == 0) cout << 0 << endl;
		else if (sum_0 == 1) cout << 1 << endl;
		else cout << 2 << endl;
	}
	return 0;
}

Codeforces 1566C 题目链接:点击这里传送

在这里插入图片描述
题意:
给出两行只包含01的字符串(看成整体),将他们分成若干个子串,使得这些子串中的未出现的数的最小值的和最打
思路:
一共就三种情况,分别讨论:

  • 10或01,这种情况最简单,直接单拿出来贡献+2
  • 11,根据下一个数的值进行分类讨论
    1.下一个数为10或01,贡献+0
    2.下一个数为00,此时分开来贡献为1,合起来为2,所以贡献+2
    3.下一个数为11,贡献+0
  • 00,根据下一个数的值进行分类讨论
    1.下一个数为10或01,贡献+1
    2.下一个数为11,贡献+2
    3.下一个数为00,贡献+1

注意合并起来的时候下标序号是+2而不是+1.

#include<bits/stdc++.h>
using namespace std;
int t, n;
string s1, s2;
//1 1 最没用
//0 0 +1
//1 0 是2
//想办法让11 和 00 凑一起
//只有00的下一个是11才处理,00和10都不处理
//10直接不处理+2
//11只有碰到00才处理,否则直接无视
int main()
{
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	cin >> t;
	while (t--)
	{
		int sum = 0;
		cin >> n;
		cin >> s1 >> s2;
		int i = 0;
		while (i < n)
		{
			if (s1[i] == '0' && s2[i] == '1' || s1[i] == '1' && s2[i] == '0')
			{
				sum += 2;
				i++;
			}
			else if (s1[i] == '1' && s2[i] == '1')
			{
				if (i == n - 1) break;
				if (s1[i + 1] == '0' && s2[i + 1] == '0')
				{
					sum += 2;
					i += 2;
				}
				else i++;
			}
			else if (s1[i] == '0' && s2[i] == '0')
			{
				if (i == n - 1)
				{
					sum++;
					break;
				}
				if (s1[i + 1] == '1' && s2[i + 1] == '1')
				{
					sum += 2;
					i += 2;
				}
				else
				{
					sum++;
					i++;
				}
			}
		}
		cout << sum << endl;
	}

	return 0;
}

Codeforces 1566D1 题目链接:点击这里传送

在这里插入图片描述
题意:
根据顺序输入m个人的视力,视力好的人坐后边,视力差的人坐前面。定义inconvenience为一个人走到其位置上所需要打扰的人的个数。现需要你根据规则安排这些人的座位,使得所有人的inconvenience的和最小。
思路:
视力相同的人,让先来的人坐后面,这样不会增加后来的人的Inconvenience,这样贪心可以让inconvenience最小。排序完后根据入场顺序模拟一遍下来,统计当前时间在其位置的左边的人数即为这个人的inconvenience。

#include<bits/stdc++.h>
using namespace std;
#define MAXN 305
int t, n, m, ans;
int visit[MAXN];//该座位上有没有人
struct node
{
	int sight;
	int id;//原来的位置
	int seat;//应该做的位置
}a[MAXN];
bool cmp2(node a, node b)
{
	if (a.sight == b.sight) return a.id > b.id;    //先来的排后面
	return a.sight < b.sight;
}
bool cmp(node a, node b)
{
	return a.id < b.id;
}
int get_inconvenience(int x)//求1~x-1有多少人已经占了位置
{
	int res = 0;
	for (int i = 1; i < x; i++) res += visit[i];
	return res;
}
int main()
{
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	cin >> t;
	while (t--)
	{
		cin >> n >> m;
		ans = 0;
		memset(visit, 0, sizeof(visit));
		memset(a, 0, sizeof(a));
		for (int i = 1; i <= m; i++) 
		{
			a[i].id = i;
			cin >> a[i].sight;
		}
		sort(a + 1, a + 1 + m, cmp);
		for (int i = 1; i <= m; i++) a[i].seat = i;
		sort(a + 1, a + 1 + m, cmp2);
		for (int i = 1; i <= m; i++)
		{
			ans += get_inconvenience(a[i].seat);
			visit[a[i].seat] = 1;
		}
		cout << ans << endl;
	}
	return 0;
}

Codeforces 1566D2 题目链接:点击这里传送

在这里插入图片描述
题意:
与D1唯一不同的是,D1只有一排,D2有n排。视力差的坐右下,视力好的坐左上。
思路:
讨论视力相同的人的座位的分布情况。

  • 如果这些相同的人坐在一排的后面,那么先来的坐后面。这样可以减少后来的视力相同的人的inconvenience,却不会影响其他人的inconvenience。
  • 如果这些相同的人坐在一排的前面。那么先来的坐后面。这样可以减少后来的视力相同的人的inconvenience,却不会影响其他人的inconvenience,因为无论这些视力相同的人怎么坐,那些坐在后面的人都要跨过前排的人。
  • 如果这些视力相同的人坐满了一整排,那么先来的坐后面,这样可以减少后来的视力相同的人的inconvenience。

由此可见,无论何种情况,都是视力相同的人中先来的人坐后面。
先整体按照视力大小排序一遍,再一排排根据上述结论细致地排序一遍,把inconvenience统计下来并输出。

#include<bits/stdc++.h>
using namespace std;
#define MAXN 305
struct node
{
	int id;//本来的位置
	int sight;
	int seat;//应该做的位置
}a[MAXN*MAXN];
int n, m, t,ans;
bool cmp(node a, node b)
{
	if (a.sight == b.sight) return a.id < b.id;
	return a.sight < b.sight;
}
int main()
{
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	cin >> t;
	while (t--)
	{
		cin >> n >> m;
		ans = 0;
		memset(a, 0, sizeof(a));
		for (int i = 1; i <= n; i++)
		{
			for (int j = 1; j <= m; j++)
			{
				a[(i - 1) * m + j].id = (i - 1) * m + j;
				cin >> a[(i - 1) * m + j].sight;
			}
		}
		sort(a + 1, a + 1 + n * m, cmp);
		for (int i = 1; i <= n * m; i++) a[i].id = -a[i].id;
		for (int i = 0; i < n; i++)//每一排单独处理(视力相同情况下,先来的往后面做)
		{
			sort(a + 1 + i * m, a + 1 + (i + 1) * m, cmp);
			for (int j = 1; j <= m; j++)
			{
				for (int k = 1; k < j; k++)
				{
					if (a[i * m + k].id > a[i * m + j].id) ans++;
				}
			}
		}
		cout << ans << endl;
	}
	
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值