ARC225 A/B/D

Posted on 2026-07-26 14:03  K_J_M  阅读(8)  评论(0)    收藏  举报

松边独鹤无余事,江上孤帆有远心

题目质量雀氏好,这里来讲一下其中的一部分。

A Four Coloring

有一个很巧妙的方法,将 \(x\) 中的 \(1,2,3,4\) 映射成 \(2,4,1,3\),现在观察每一组相邻的 \(x\),会发现全部符合条件,于是做完了。时间复杂度为 \(\mathcal O(n)\)

#include<bits/stdc++.h>
using namespace std;
const int N = 5e2+10;
int n,a[N][N];
int main(){
	cin>>n;
	for(int i=1;i<=n;++i){
		for(int j=1;j<=n;++j){
			cin>>a[i][j];
			if(a[i][j]==1)cout<<3<<" ";
			if(a[i][j]==2)cout<<1<<" ";
			if(a[i][j]==3)cout<<4<<" ";
			if(a[i][j]==4)cout<<2<<" ";
		}
		cout<<"\n";
	}
	return 0;
}

B - Independent Nim

好题。

我们会发现原数列一定是若干段连续的 \(1\) 组成的数列,于是我们先考虑全部是 \(1\) 的情况。

对于两个 \(1\) 显然后手必胜。对于三个,先手先取走边上的 \(1\),然后就来到了前面的情况。对于四个,先手先取走边上的两个就来到两个的情况。对于五个,先手取走中间一个,那么原数列就划分为有两段连续的 \(1\) 的且每一段只有两个 \(1\),对于这种情况,无论取走什么,后者只需将单独的 \(1\) 取走就又成为只有连续的两个 \(1\) 的局面。于是我们单独考虑这种情况。

假设现在连续的 \(1\) 有两个的段数为 \(n\),先手可以取走 \(n,n-1,n-2\dots 1\)\(1\),于是会剩下 \(n,n-1\dots 1\) 个单独的 \(1\),那么后者继续将单独的 \(1\) 给取走就回到有 \(m\) 个连续的 \(1\) 有两个的段了。而我们又知道 \(m=1\)\(m=2\) 是先手必败的,于是我们依照数学归纳法可知对于 \(n\) 也是必败的。

回到本题,我们说如果先手不是必败局面,那么一定存在一种方法使得后手处于必败局面,也就是取走若干个 \(1\) 使得化为 \(n\) 个连续的 \(1\) 的个数为 \(2\)。但当全部为 \(0\) 时先手必败。时间复杂度为 \(\mathcal O(n)\).

#include<bits/stdc++.h>
using namespace std;
const int N  = 2e5+10;
int t,n,a[N];
int main(){
	cin>>t;
	while(t--){
		cin>>n;
		for(int i=1;i<=n;++i)cin>>a[i];
		if(n==2){
			if(a[1]==a[2]){
				puts("Bob");
			}else{
				puts("Alice");
			}
		}else{ 
			bool ok=0;
			for(int i=1;i<=n;++i){
				if(a[i]==1){
					int pos=i;
					while(pos<=n&&a[pos]==1)++pos;
					--pos;
					if(pos-i+1!=2){
						ok=1;
						break;
					}
					i=pos;
				}
			}
			if(ok)puts("Alice");
			else puts("Bob");
		}
	}
	return 0;
}

D - Gap Swap (easy)

简单版。但是对我有点困难

有一种方法是构造函数,这种函数满足目标局面的值确定(一般为 \(0\) 或者是一个上界),且每一步操作只会增加或减少。对于本题而言每个元素 \(P_i\) 的目标值为 \(i\),于是我们对差值求和,令

\[f(P)=\sum_{i=1}^{n}|P_i-i| \]

接下来的步骤就是考虑每一步操作的改变量。

我们说一次最优的操作只有可能是 \(j,i+1,i+2\dots j-1,i\),这很简单说明,于是我交换的减小量是 \(2\times (j-i)\),代价是 \(j-i\),由于我的减小量和代价之间一直是两倍关系,且我最终的减小量一定是 \(f(P)\),所以我的代价是 \(\frac{f(P)}{2}\),十分精妙!时间复杂度为 \(\mathcal O(n)\)

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 5e5+10;
int n,p[N];
signed main(){
	cin>>n;
	int sum=0;
	for(int i=1;i<=n;++i){
		cin>>p[i];
		sum+=abs(p[i]-i);
	}
	cout<<sum/2;
	return 0;
}