Codeforces Round #691 (Div. 2)ABC——解题报告

本文解析了CodeForces 1459题目的三道题:A-Red-Blue Shuffle通过比较字符大小得出结果;B-Move and Turn介绍了两种解法:动态规划和数学公式;C-Row GCD利用更相减损法求解最大公约数问题。

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

比赛链接

https://codeforces.com/contest/1459

A - Red-Blue Shuffle 

直接求出ai>bi和ai<bi的个数就行了,如果ai>bi比较多则输出RED,如果ai<bi比较多则输出BLUE,相等的话输出EQUAL

证明:首先ai==bi的情况不用考虑,因为不论怎么排列,对应位置都是相等的。

然后考虑ai>bi的情况,当ai和bi都在第一位时,RED的个数会加一,ai<bi的情况同理。

最后比较一下RED的个数和BLUE的个数就行了。

详细证明参考题解:https://codeforces.com/blog/entry/85750

#include <bits/stdc++.h>
#define PI atan(1.0)*4
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pil pair<int,ll>
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define LINF 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
using namespace std;
int debug = 0;
ll gcd(ll a,ll b){
	return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b){
	return a/gcd(a,b)*b;
}
inline int read(){
	int s=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*f;
}
const int N = 1e5+7;
int a[N],b[N];
void solve(){
	int n=read();
	string s1,s2;cin>>s1>>s2;
	int cnt1=0,cnt2=0;
	rp(i,0,n-1){
		if(s1[i]<s2[i]) cnt1++;
		if(s1[i]>s2[i]) cnt2++;
	}
	if(cnt1==cnt2) puts("EQUAL");
	else if(cnt1>cnt2) puts("BLUE");
	else puts("RED");
}
int main(){
	//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
	freopen("in.txt", "r", stdin);
	//debug = 1;
#endif
	time_t beg, end;
	//if(debug) beg = clock();

	int T=read();
	while(T--) solve();

	/*
	if(debug) {
		end = clock();
		printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
	}
	*/
	return 0;
}

B - Move and Turn

比赛时打了个前10的表,然后oeis了一发,按照上面的公式交了一发,没想到过了。。

这个题由两个做法:dp或者公式。

公式的证明参考题解,讲的很详细了。

公式的做法

#include <bits/stdc++.h>
#define PI atan(1.0)*4
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pil pair<int,ll>
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define LINF 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
using namespace std;
int debug = 0;
ll gcd(ll a,ll b){
	return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b){
	return a/gcd(a,b)*b;
}
inline int read(){
	int s=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*f;
}
void solve(){
	ll n;scl(n);
	ll ans;
	if(n&1) ans=1+(3*n*(n+4)+2+(n*(n + 4)+2))/8;
	else ans=1+(3*n*(n+4)+2-(n*(n +4)+2))/8;
	cout<<ans<<endl;
}
int main(){
	//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
	// freopen("in.txt", "r", stdin);
	//debug = 1;
#endif
	time_t beg, end;
	//if(debug) beg = clock();
	solve();
	/*
	if(debug) {
		end = clock();
		printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
	}
	*/
	return 0;
}
/*
1 4
2 4
3 12
4 9
5 24
6 16
7 40
8 25
9 60
10 36
11 84
12 49
13 112
14 64
15 144
16 81
17 180
18 100
19 220
20 121
21 264
22 144
23 312
24 169
25 364
26 196
*/

C - Row GCD

比赛时打了个表,找到了循环节的假规律,不过循环节的长度一直找不到公式,然后这道题就没了。

这个题的关键都基于一个公式(更相减损法):gcd(a,b)=gcd(a,b-a),这里假设a<b。

首先可以知道一个公式:gcd(a,b,c)=gcd(gcd(a,b),c)=gcd(a,gcd(b,c)),这里假设a<b<c。

那么应用到多个变量的公式就是:

gcd(a,b,c)\Rightarrow gcd(a,gcd(b,c))\Rightarrow gcd(a,gcd(b,c-b))\Rightarrow gcd(a,b,c-b) \Rightarrow gcd(gcd(a,b),c-b)\Rightarrow gcd(gcd(a,b-a),c-b)

\Rightarrow gcd(a,b-a,c-b)

至于为什么gcd(a,gcd(b,c-b))\Rightarrow gcd(a,b,c-b)是成立的?

首先可以知道gcd(a,gcd(b,c)))\Leftrightarrow gcd(a,gcd(b,c-b)),然后既然b和c的最大公约数等于b和c-b的最大公约数,因为我们最后还要和a再取一个最大公约数,那么就可以用b和c-b替代b和c,反正他们两个的作用都是提供他们俩的最大公约数,而且最大公约数都相等,所以为了方便可以进行替换。

这样的话,对于题目给的公式我们就可以进行转换,这里默认a_{1}<=a_{2}<=...<=a_{n}

\gcd(a_1, a_2, \cdots, a_{n-2}, a_{n-1}, a_n) \\ \Rightarrow \gcd(a_1, a_2, \cdots, a_{n-2}, \gcd(a_{n-1}, a_n)) \\ \Rightarrow \gcd(a_1, a_2, \cdots, a_{n-2}, \gcd(a_{n-1}, a_n-a_{n-1})) \\ \Rightarrow \gcd(a_1, a_2, \cdots, a_{n-2}, a_{n-1}, a_n-a_{n-1}) \\ \Rightarrow \gcd(a_1, a_2, \cdots, \gcd(a_{n-2}, a_{n-1}), a_n-a_{n-1}) \\ \Rightarrow \gcd(a_1, a_2, \cdots, \gcd(a_{n-2}, a_{n-1}-a_{n-2}), a_n-a_{n-1}) \\ \Rightarrow \gcd(a_1, a_2, \cdots, a_{n-2}, a_{n-1}-a_{n-2}, a_n-a_{n-1}) \\ \cdots \\ \Rightarrow \gcd(a_1, a_2-a_1, \cdots, a_{n-1}-a_{n-2}, a_n-a_{n-1})

最终结果就是:

gcd(a_{1}+b_{j},a_{2}+b_{j},...,a_{n}+b_{j})\Rightarrow gcd(a_{1}+b_{j},a_{2}-a_{1},...,a_{n}-a_{n-1})

因此我们可以先对a数组进行排序,然后再O(n)维护出gg=gcd(a_{2}-a_{1},...,a_{n}-a_{n-1})

再枚举b[j],最终答案就是gcd(gg,a_{1}+b_{j})

trick:注意gg要初始化为0,因为只有0能被其他所有数整除,1不符合条件,因为1不能被0整除。这里有点不好理解。

其实也当时找的循环节的长度就是gcd(a_{2}-a_{1},...,a_{n}-a_{n-1}),不过找出来也会超时。

#include <bits/stdc++.h>
#define PI atan(1.0)*4
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pil pair<int,ll>
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define LINF 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
using namespace std;
int debug = 0;
ll gcd(ll a,ll b){
	return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b){
	return a/gcd(a,b)*b;
}
inline int read(){
	int s=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*f;
}
const int N = 2e5+7;
ll a[N],b[N];
ll ans[N];
void solve(){
	int n=read(),m=read();
	rp(i,1,n) scl(a[i]);
	rp(i,1,m) scl(b[i]);
	sort(a+1,a+1+n);
	ll gg=0;
	rp(i,2,n) gg=gcd(gg,a[i]-a[i-1]);
	rp(j,1,m) printf("%lld%s",gcd(gg,a[1]+b[j]),j==m?"\n":" ");
}
int main(){
	//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
	freopen("in.txt", "r", stdin);
	//debug = 1;
#endif
	time_t beg, end;
	//if(debug) beg = clock();

	int T=1;
	while(T--) solve();

	/*
	if(debug) {
		end = clock();
		printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
	}
	*/
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值