Codeforces Round #691 (Div. 2) A~C题解

博客分享了三道算法题的解题思路。A题比较红比蓝大与蓝比红大的个数确定概率;B题先确定第一步,计算x、y轴不同终点数相乘得平面终点数,根据n奇偶性处理答案;C题利用gcd性质预处理式子,注意排序和特判情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

A-Red-Blue Shuffle

水题,速切。
比一比红比蓝大的个数和蓝比红大的个数,大的那个概率大。

#include<bits/stdc++.h>
#define ll long long
#define inf 1<<30
using namespace std;
char r[1010],b[1010];
int main()
{
	int T,n;
	scanf("%d",&T);
	while(T--){
		scanf("%d",&n);
		scanf("%s%s",r,b);
		int cntr=0,cntb=0;
		for(int i=0;i<n;i++){
			if(r[i]>b[i]) cntr++;
			else if(r[i]<b[i]) cntb++;
		}
		if(cntr>cntb) puts("RED");
		else if(cntr<cntb) puts("BLUE");
		else puts("EQUAL");
	}
}

B-Move and Turn

应当面壁思过,考场上为什么卡了那么久,捶了dfs还找不出规律。
这里说明一下,本题我不是找规律过的,是真的想出了做法。

先考虑一个问题,我第一步确定之后,之后沿x轴走和沿y轴走的步数是固定的。
于是我就先考虑点在横坐标上的移动,每一步相当于是+1或者-1,也就是说给定了步数(比如说a步),每一步可以+1或者-1,求最终可以到达的数是多少,很容易可以发现,最左到达a,最右是-a。把每个+1换成-1会使最终的点向左移动2格,因此最终能到达的不同格子是:
( a − ( − a ) ) / 2 + 1 = a + 1 (a-(-a))/2+1=a+1 (a(a))/2+1=a+1
因此,对于确定的步数,可以得出在x轴上的不同终点数。同理y轴也可以同样的方法得出。

于是,如果第一步确定之后,就可以将两个轴上的终点个数一乘,就是平面中终点的个数了。

所以枚举第一步是沿x轴走还是y轴走。

最终答案时,如果n为奇数,那么先向x轴还是y轴是有区别的,此时恰好将两种答案错开。如果n为偶数,则哪个先走无所谓,所以答案会重合,要除以2。

#include<bits/stdc++.h>
#define ll long long
#define inf 1<<30
using namespace std;
ll getit(int x,int y){
	ll xt,yt;
	xt=x+1;yt=y+1;
	return xt*yt;
}//在x轴上走x步,y轴上走y步时,平面中不同的终点数
int main()
{
	int n;
	scanf("%d",&n);
	int x=(n+1)/2,y=n/2;//先走x
	ll ans=0;
	ans+=getit(x,y);
	x=n/2,y=(n+1)/2;//先走y
	ans+=getit(x,y);
	if(n&1)
		printf("%lld\n",ans);
	else printf("%lld\n",ans/2);//若为偶数,则两次算的终点是重合的,除以2
}

C-Row GCD

我承认,考场上看到 1 0 18 \color{Red}{10^{18}} 1018就吓坏了。
其实很简单(就是坑多)。
考虑其特性,gcd中每一项都加上了一个相同的数,每次都重算是不现实的,因此,如果能预处理,那再好不过了。于是,gcd的性质中有一条能把加上的数刚好减去。
gcd ⁡ ( a , b ) = gcd ⁡ ( a − b , b ) \gcd(a,b)=\gcd(a-b,b) gcd(a,b)=gcd(ab,b)

设g=gcd(a,b)
则ab可以表示为
a=x*g,b=y*g
则a-b=(x-y)*g
已知x与y互质,可得 x-y与y也互质(见下)
所以gcd(a-b,b)=g=gcd(a,b)

已知x与y互质,假设 x-y与y不互质
则有
x-y=a*k,y=b*k,k>1
所以,x=(a+b)*k
得gcd(x,y)=k>1,与条件不符

证明过程放在这里,便于越来越菜的我之后回来复习
所以,对于式子
gcd ⁡ ( a 1 + b , a 2 + b , … , a n + b ) \gcd(a_1+b,a_2+b,\dots,a_n+b) gcd(a1+b,a2+b,,an+b)
可以将前两项拿出来看看,就是 gcd ⁡ ( a 1 + 1 , a 2 + 1 ) = gcd ⁡ ( a 1 − a 2 , a 2 + 1 ) \gcd(a_1+1,a_2+1)=\gcd(a_1-a_2,a_2+1) gcd(a1+1,a2+1)=gcd(a1a2,a2+1)
所以,整个式子就变成了如下的鸭子:
gcd ⁡ ( a 1 − a 2 , a 2 − a 3 , … , a n − 1 − a n , a n + b ) \gcd(a_1-a_2,a_2-a_3,\dots,a_{n-1}-a_n,a_n+b) gcd(a1a2,a2a3,,an1an,an+b)
所以对于每个b,只要先预处理出前面的一坨,就可以 O ( l o g 1 e 18 ) O(log1e18) O(log1e18),解决。
W A , R E p o i n t s : \color{Red}{WA,REpoints:} WAREpoints
注意,要先将a从大到小

要特判n=1和前面的一坨gcd=0的情况。

#include<bits/stdc++.h>
#define ll long long
#define inf 1<<30
using namespace std;
const int MAXN=2e5+10;
ll gcd(ll x,ll y){return x%y==0?y:gcd(y,x%y);}
ll a[MAXN],b[MAXN];
bool cmp(ll x,ll y){return x>y;}
int main()
{
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
	for(int i=1;i<=m;i++) scanf("%lld",&b[i]);
	sort(a+1,a+1+n,cmp);
	ll gd=0;
	for(int i=1;i<n;i++){
		if(a[i]-a[i+1]==0) continue;//0不要参与gcd的运算,小心nan
		if(gd==0) gd=a[i]-a[i+1];
		gd=gcd(gd,a[i]-a[i+1]);
	}
	for(int i=1;i<=m;i++){
		if(n==1||gd==0) printf("%lld ",a[n]+b[i]);
		else printf("%lld ",gcd(gd,a[n]+b[i]));
	}
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值