ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Educational Codeforces Round 110 (Div. 2) 个人题解

2021-06-05 11:31:26  阅读:164  来源: 互联网

标签:p2 pre Educational p1 int 题解 Codeforces beautiful 问号


在这里插入图片描述

C题过得确实有点惊险哈,快1:57才过,只剩三四分钟了……

A. Fair Playoff

题意

给a,b,c,d四个人的能力值,然后a,b较量,c,d较量,赢的人再进入决赛。问决赛的两人是不是能力值最大的,是就公平,不是就不公平
分析

嘛,怎么写都可以吧
给一份相对复杂的代码

#include <bits/stdc++.h>
#define fors(i, a, b) for(int i = (a); i <= (b); ++i)
#define lson k<<1
#define rson k<<1|1
#define pb push_back
#define lowbit(x) ((x)&(-(x)))
#define mem(a) memset(a, 0, sizeof(a))
#define IOS ios::sync_with_stdio(false), cin.tie(0)
#define int long long
const int inf = 0x3f3f3f3f;
const double dinf = 1e100;
typedef long long ll;
//const ll linf = 9223372036854775807LL;
// const ll linf = 1e18;
using namespace std;
 
signed main()
{
	IOS;
	int  t;
	cin >> t;
	while(t--)
	{
		int a, b, c, d;
		cin >> a >> b >> c >> d;
		int p[4] = {a, b, c, d};
		sort(p, p + 4, greater<int>());
		if(a < b) swap(a, b);
		if(c < d) swap(c, d);
		if(a < c) swap(a, c);
		if(a == p[0] && c == p[1]) cout << "YES" << endl;
		else cout << "NO" << endl;
	}
	return 0;
}

B. Array Reodering

题意

给定一个数组,现在要你重排这个数组,使得有最多的数对,满足:
1 ≤ i < j ≤ n , g c d ( a i , 2 a j ) > 1 1≤i<j≤n, gcd(a_i,2a_j)>1 1≤i<j≤n,gcd(ai​,2aj​)>1
分析

贪心。由于数据只有2000,凹了一个 O ( n 2 ) O(n^2) O(n2)的贪心QWQ。先不看条件 1 ≤ i < j ≤ n 1≤i<j≤n 1≤i<j≤n,算出每个数和其他所有数最多形成的数对。然后,如果我们加上了条件 1 ≤ i < j ≤ n 1≤i<j≤n 1≤i<j≤n,那么每个数肯定会损失一些数对。贪心的构造是让整个数组损失的数对最小。那么可以猜想,结果是按每个数原本的数对个数降序排序。

粗略证明

(昨天随便想的,但感觉不太严格)

由于把“和其他所有数最多形成的数对”最大的数排在了第一个,故这个最大的数肯定不会有任何损失。进一步地思考,把形成数对大的尽量放前面,其后面的数就越多,前面的数就越少,其原本的数对满足 1 ≤ i < j ≤ n 1≤i<j≤n 1≤i<j≤n的机会就越多,所以损失的数对就会越少。因为形成数对大的数损失的机会是更大的,所以需要把它们放在前面,减少损失机会。

代码

#include <bits/stdc++.h>
#define fors(i, a, b) for(int i = (a); i <= (b); ++i)
#define lson k<<1
#define rson k<<1|1
#define pb push_back
#define lowbit(x) ((x)&(-(x)))
#define mem(a) memset(a, 0, sizeof(a))
#define IOS ios::sync_with_stdio(false), cin.tie(0)
#define int long long
const int inf = 0x3f3f3f3f;
const double dinf = 1e100;
typedef long long ll;
//const ll linf = 9223372036854775807LL;
// const ll linf = 1e18;
using namespace std;
const int maxn = 2005;
int n;
struct node{
	int x, cnt;
	node(){
		x = cnt = 0;
	}
}a[maxn];
bool cmp(node x, node y){
	return x.cnt > y.cnt;
}
signed main()
{
	IOS;
	int  t;
	cin >> t;
	while(t--)
	{
		int ans = 0;
		cin >> n;
		fors(i, 1, n) cin >> a[i].x, a[i].cnt = 0;
		fors(i, 1, n){
			fors(j, 1, n){
				if(i == j) continue;
				if(__gcd(a[i].x, a[j].x * 2) > 1){
					a[i].cnt++;
				}
			}
		}
		sort(a + 1, a + 1 + n, cmp);
		fors(i, 1, n){
			a[i].cnt = 0;
		}
		fors(i, 1, n){
			fors(j, i + 1, n){
				if(__gcd(a[i].x, a[j].x * 2) > 1){
					ans++;
				}
			}
		}
		cout << ans << endl;
	}
	return 0;
}

C. Unstable String

题意

(题意稍微有点难理解)

给一个字符串,其含有’0’,‘1’,’?’. 其中,’?‘可以看成’1’,也可以看成’0’。如果一个字符串可以是0和1交替出现的,就称这个字符串是 b e a u t i f u l beautiful beautiful。问现在这个字符串有多少 b e a u t i f u l beautiful beautiful的子串?

例如,
字符串1,10是beautiful的;
字符串1???1也是beautiful的,因为通过问号可以转化为10101;
但字符串1???1不是beautiful的,因为通过问号不管怎么变,都不可能使得01交替出现。

分析

我的做法是双指针。(开局就想到了,但奈何我的讨论不细致,导致一个多小时以后才终于AC)

设两个指针 p 1 p1 p1, p 2 p2 p2,都从 0 0 0开始,然后 p 2 p2 p2前移,期间检查 p 1 p1 p1到 p 2 p2 p2是否可以组成一个 b e a u t i f u l beautiful beautiful的子串,如果可以就继续前移。

如何判断呢?我的做法是:

首先预处理,对每个连续的问号段,维护这整个问号段前面的那个数字。

为什么这样维护呢? 可以发现,当一个问号段长度是奇数时,如果其左右的数字都相同,那么一定可以把问号替换成数字,使得问号串加上两个数字仍然是 b e a u t i f u l beautiful beautiful的。例如,1???1可以替换成10101。反之,如果两端的数字不同,那么这个问号段就不可能保证加上两端的数字后还能 b e a u t i f u l beautiful beautiful。 对于问号段长度为偶数的情况则恰好相反。特别注意,如果问号段位于整个字符串的最左/最右端,那么它是肯定符合条件的

所以,判断问号后面的数字可不可以接,关键是看这个数字和问号段最前面的数字的关系,预处理出来即可。之后再讨论可否前移就比较清晰了。

例如,对于10011???,对于问号段"???",其 p r e [ i ] = 4 pre[i]=4 pre[i]=4,表示最前面的数字下标为4.


那如果通过判断,发现 p 2 p2 p2左移后不能保证 [ p 1 , p 2 ] [p1,p2] [p1,p2]仍然 b e a u t i f u l beautiful beautiful,该怎么办呢?

  1. 如果 p 2 p2 p2和 p 2 + 1 p2+1 p2+1都不是问号,说明这是两个相等的数字,无论如何它们都不能连在一起了,直接算出 p 1 p1 p1到 p 2 p2 p2的答案加到 a n s ans ans中。 p 1 p1 p1到 p 2 p2 p2的所有子串都是符合条件的,所以答案是 ∑ i = 1 p 2 − p 1 + 1 i \sum_{i=1}^{p2-p1+1}i ∑i=1p2−p1+1​i,一个等差数列和。最后把 p 2 p2 p2右移,然后令 p 1 = p 2 p1=p2 p1=p2(原来的区间已经统计完毕,可以彻底抛弃掉了)
  2. 如果 p 2 p2 p2是问号, p 2 + 1 p2+1 p2+1不是问号,说明 p 2 p2 p2所在的问号段的前面那些已经不可能再接上了。但是,从 p r e [ p 2 ] + 1 pre[p2]+1 pre[p2]+1到 p 2 p2 p2这个问号段不一定不再起作用,但可以肯定的是从 p 1 p1 p1到 p r e [ p 2 ] pre[p2] pre[p2]肯定不需要了,因此统计出 p 1 p1 p1到 p r e [ p 2 ] pre[p2] pre[p2]的等差和。 这个时候不要急着令 p 1 = p r e [ p 2 ] + 1 p1=pre[p2]+1 p1=pre[p2]+1,而要考虑,从 p 1 p1 p1到 p r e [ p 2 ] pre[p2] pre[p2],其和 p r e [ p 2 ] pre[p2] pre[p2]到 p 2 p2 p2仍然可以相连,组成 b e a u t i f u l beautiful beautiful串,记得把这些也统计进来。之后再令 p 1 = p r e [ p 2 + 1 ] p1=pre[p2+1] p1=pre[p2+1]。

代码

#include <bits/stdc++.h>
#define fors(i, a, b) for(int i = (a); i <= (b); ++i)
#define lson k<<1
#define rson k<<1|1
#define pb push_back
#define lowbit(x) ((x)&(-(x)))
#define mem(a) memset(a, 0, sizeof(a))
#define IOS ios::sync_with_stdio(false), cin.tie(0)
#define int long long
const int inf = 0x3f3f3f3f;
typedef long long ll;
//const ll linf = 9223372036854775807LL;
// const ll linf = 1e18;
using namespace std;
const int maxn = 2e5 + 10;
int n;
string s;
int cnt(int len)
{
	return (len + 1) * len / 2LL;
}
int cnt(int l, int r)
{
	return (r - l + 1) * (r - l + 2) / 2LL;
}
int pre[maxn];
signed main()
{
	IOS;
	// 前缀处理:对每个?,找其公共序列的最前面一个非问号
	int  t;
	cin >> t;
	
	while(t--)
	{
		// 0和1肯定不能连续. 对于?,按整个问号序列长度定
		// 双指针
		cin >> s;
		int p1 = 0, p2 = 0;
		for(int i = 0; i < s.size(); ++i){
			pre[i] = -1;
		}
		for(int i = 0; i < s.size(); ++i){
			if(i == 0 && s[i] == '?'){
				pre[i] = -1;
			}
			else if(i > 0 && s[i] == '?' && s[i - 1] == '?'){
				pre[i] = pre[i - 1];
			}
			else if(s[i] == '?'){
				pre[i] = i - 1;
			}
		}
		int ans = 0;
		for(;;){
			if(p2 + 1 >= s.size()){
				if(p2 == s.size() - 1){
					ans += cnt(p2 - p1 + 1);
				}
				break;
			}
			int flag = 1;
			if(s[p2] == '?' && s[p2 + 1] == '?');
			else if(s[p2] == '?' && pre[p2] == -1);
			else if(s[p2] == '?' && s[p2 + 1] != '?'){
				int len = p2 - pre[p2];
				if(len % 2 == 0 && s[p2 + 1] != s[pre[p2]]);
				else if(len % 2 != 0 && s[p2 + 1] == s[pre[p2]]);
				else flag = -1;
			}
			else if(s[p2] != '?' && s[p2] == s[p2 + 1]) flag = 0;
			if(flag == 1) p2++;
			else if(flag == 0){
				ans += cnt(p2 - p1 + 1);
				p2++;
				p1 = p2;
			}
			else{
				ans += cnt(pre[p2] - p1 + 1) + (pre[p2] - p1 + 1) * (p2 - pre[p2]);
				p1 = pre[p2] + 1;
				p2++;
			}
		}
		cout << ans << endl;
	}
	return 0;
}

Love Sakurai Yamauchi forever!!!

标签:p2,pre,Educational,p1,int,题解,Codeforces,beautiful,问号
来源: https://blog.csdn.net/qq_39561693/article/details/117588239

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有