2021-11-22 Educational Codeforces Round 117 Div2

这篇博客回顾了一场Codeforces比赛,作者参与了Div2的A、B两题,分别涉及曼哈顿距离的计算和特殊排列问题。A题通过分析奇偶性快速找到满足条件的点C;B题通过构造排列,确保a和b的位置满足题意。此外,还提及了C题的二分搜索解法和D题的数学操作。
摘要由CSDN通过智能技术生成

很久没打过codeforces了,荒废了大半年,不够努力。
希望以后每天都至少写一题,div2、div3的如果没有别的事情冲突的话每场都打一打。
这是我打的第三场cf,延续以往传统,只做出了A、B两道简单题。
加了173分,新手第3场送了250分…现在891分。

官方题解

A.Distance

题目链接

题意: 对于点p1(x1,y1),p2(x2,y2),定义曼哈顿距离d(p1,p2) = |x1-x2| +|y1-y2|。
A点坐标(0,0),给出多组B点坐标(x,y),0<=x,y<=50,都是整数。
问:是否存在点C,使得d(A,C)= d(A,B)/ 2, d(B,C)= d(A,B)/ 2 。
存在则输出C点坐标,否则输出"-1 -1"。

签到题,官方题解是让x,y在0-50遍历所有整数,看是否有解。

个人思路:
因为A点始终是(0,0),
①如果x和y奇偶性不一样时,可知是没有整数解的,因为此时d(A,B)是个奇数,它的一半不是整数。
②如果x,y均为偶数,输出(x/2,y/2)即可。
③如果x,y均为奇数,
若x>y,则y不变,输出((x+y)/ 2 - y,y);
若x<y,则x不变,输出(x,(x+y)/ 2 - x)。

#include<iostream>
using namespace std;
int main()
{
	int t,x,y;
	cin>>t;
	while(t--)
	{
		cin>>x>>y;
		if((x+y)%2==1)
			cout<<"-1 -1"<<endl;
		else 
		{
			if(x%2==0&&y%2==0)
				cout<<x/2<<" "<<y/2<<endl;
			else if(x%2==1&&y%2==1)
			{
				if(x>y)
					cout<<(x+y)/2-y<<" "<<y<<endl;
				else 
					cout<<x<<" "<<(x+y)/2-x<<endl;				
			}
		}
		
	}
	return 0;
}

B.Special Permutation

题目链接

题意: 多组样例,每组输出三个整数n,a,b,n为偶数。
是否存在一个1-n的排列(可以是乱序),把它分成两部分,使得a在左半部分,且左半部分的数都比a大;使得b在右半部分,且右半部分的数都比b小。
存在则输出满足条件的1个排列,否则输出-1 。

若存在这样的排列,首先得满足1<=a<=n/2,n/2<=b<=n。
把a放在第一位,然后左半部分从最大的数开始放(不能放b),看左半部分是否能再放n/2-1个比a大的数;
把b放在最后一位,然后右半部分从最小的数开始放(不能放a),看右半部分是否能再放n/2-1个比b小的数,显然,已经在左边放过的数不能再放。
判断是否满足上述条件,所有的数都用了即可。

#include<iostream>
#include<cstring>
using namespace std;

int main()
{
	int t,n,a,b,x[105],y[105],k;
	cin>>t;
	while(t--)
	{
		cin>>n>>a>>b;
		memset(x,0,sizeof(x));    //判断该数是否已经用过,0没用过,1用过
		memset(y,0,sizeof(y));
		k = 0;   
		if(n-a>=(n/2-1) && b>=n/2 && a!=b)  //基本条件
		{
			y[k++] = a;
			x[a]=1;
			for(int i = n,j = 0; i >= 1&& j < n/2-1; i--)   //放左半部分
				if(i!=b&&i!=a)
				{
					if(i>a)
					{
						y[k++] = i;
						x[i] = 1;
						j++;
					}
				}
			if(k!=n/2)   //左边放了n/2个数并且满足条件
			{
				cout<<"-1"<<endl;
				continue;
			}
			//cout<<endl;
			for(int i = 1; i <= n; i++)   //放右半部分
				if(x[i]==0&&i<=b)
				{
					y[k++] = i;
				}
					
					
			if(k==n)   //所有的数都用了
			{
				for(int i = 0; i < n; i++)
				{
					if(i==0)
						cout<<y[i];
					else
						cout<<" "<<y[i];
				}
				cout<<endl;
			}	
			else 
				cout<<"-1"<<endl;
		}
		else 
			cout<<"-1"<<endl;
		
	}
	return 0;
}

C.Chat Ban

题目链接

标签:二分搜索,数学。
二分好久没写了,生疏了,题目本身不难。

题意: 给定k和x,你想发送2*k-1条消息,每条消息包括多个表情:1,2,3,…,k,k-1,k-2,…,2,1 。
但是发送大于等于x个表情后就会被禁止发言。 问:对于给定的k和x,最多能够发送多少条消息?

参考官方题解如下:

#include<bits/stdc++.h>
using namespace std;
long long get(int x)
{
	return x*1ll*(x+1)/2;    //等差数列 
}
int main()
{
	int t,k;
	long long x;
	cin>>t;
	while(t--)
	{
		cin>>k>>x;
		//二分法 
		long long l = 1, r = 2*k-1;
		long long res = 2*k-1;  //总共有2*k-1行
		bool over = false;    //判断到第mid行是否超过了x 
		while(l<=r)
		{
			int mid = (l+r)/2;
			if(mid >= k)
			{
				over = (get(k) + get(k-1) - get(2*k-1-mid) >= x);
			}
			else
			{
				over = ( get(mid) >= x );
			}
			if(over)
			{
				res = mid;
				r = mid - 1;
			} 
			else
			{
				l = mid + 1;
			}
		}
		cout<<res<<endl;
	}
	
	return 0;
} 

D.X-magic Pair

题目链接
标签:数学,数论。

题意: 给定一对整数(a,b)和一个整数x,可以进行如下操作:
令a = |a-b| 或者 令b = |a-b|,
问是否可以通过有限次操作后使得 a = x 或者 b = x?

官方题解称以下算法可以生成所有可能出现的整数,但没有证明,还不太理解。

算法:
如果a<b,则交换a和b,如果b>a-b,则令b = a - b,否则一直从a中减去b;
重复上述操作,如果a = x 或者 b = x,则返回true 。
如果 a = 0 或者 b = 0,则返回false 。

#include<bits/stdc++.h>
using namespace std;

//算法,还不太理解 
bool get(long long a,long long b,long long x)
{
 	if(a == x || b == x) return true;
 	if(a < b) swap(a,b);
 	if(b > a-b) b = a-b;
 	if(x > max(a,b) || a==0 || b == 0) return false;
 	long long cnt = max(1ll, (a - max(x,b)) / (2*b));
 	return get(a - b*cnt, b, x);
}

int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		long long a,b,x;
		cin>>a>>b>>x;
		if(get(a,b,x))
			cout<<"YES"<<endl;
		else 
			cout<<"NO"<<endl;
	}
	return 0;
}

2021.11.24晚,先写4题,后面三题改日再补。

E.Messages

题目链接

F.Armor and Weapons

题目链接

G.Max Sum Array

题目链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值