Educational Codeforces Round 117 Div2
很久没打过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题,后面三题改日再补。