ARC225

赛时写了 A~D,然后第二天早上发现号没了。被 dq 了。。。尝试了申诉,但是已经准备换号了。。

一场比赛四个结论题如何评价。

A

发现限制等价于对于点 \(1,2\)

  • \(\vert x_1-x_2\vert=1\),则 \(\vert y_1-y_2\vert\geq2\)
  • \(\vert x_1-x_2\vert\geq2\),则 \(\vert y_1-y_2\vert=1\)

\(y_i\) 的取值仅仅与 \(x_i\) 有关,考虑构造一组颜色映射 \(x_i\rightarrow y_i\)。尝试一下即可构造得到:

\[1\rightarrow2\\ 2\rightarrow4\\ 3\rightarrow1\\ 4\rightarrow3 \]

回忆代码
//#include<bits/stdc++.h>
#include<algorithm> 
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
using namespace std;
constexpr const int N=500,f[5]={0,2,4,1,3};
int n,x[N+1][N+1]; 
int main(){
	/*freopen("test.in","r",stdin);
	freopen("test.out","w",stdout);*/
	
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	
	cin>>n;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			cin>>x[i][j];
			cout<<f[x[i][j]]<<' ';
		}
		cout<<'\n';
	}
	
	cout.flush(); 
	
	/*fclose(stdin);
	fclose(stdout);*/
	return 0;
}

B

显然有用的就是若干段连续的 \(1\)

手玩发现:

  • \(1\):先手必胜。
  • \(2\):后手必胜。
  • \(3\):先手必胜。
  • \(4\):先手必胜。

然后猜测只有连续段的长度为 \(2\) 时,才是后手必胜,否则先手必胜。

因为可以三个三个断开,全部变成长度为 \(2\) 的段,所以得证。

回忆代码
//#include<bits/stdc++.h>
#include<algorithm> 
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
using namespace std;
constexpr const int N=2e5;
int n,a[N+1];
int main(){
	/*freopen("test.in","r",stdin);
	freopen("test.out","w",stdout);*/
	
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	
	int T;
	cin>>T;
	while(T--){
		cin>>n;
		for(int i=1;i<=n;i++){
			cin>>a[i];
		}
		vector<int>p;
		int cnt=0;
		for(int i=1;i<=n;i++){
			if(a[i]){
				cnt++;
			}else{
				p.push_back(cnt);
				cnt=0;
			}
		}
		p.push_back(cnt);
		bool ans=false;
		for(int x:p){
			if(x!=2&&x!=0){
				ans=true;
				break;
			}
		}
		if(ans){
			cout<<"Alice\n";
		}else{
			cout<<"Bob\n";
		}
	}
	
	cout.flush(); 
	
	/*fclose(stdin);
	fclose(stdout);*/
	return 0;
}

C

假设答案已知,那么把剩下的 \(0\) 边加入后,生成树仍然在这张图里。然后再考虑删掉多余的 \(0\) 边。说废话。

因此肯定会有一些 \(1\) 边是必须的,去掉之后无论加多少 \(0\) 边都无法形成生成树。先跑一遍最小生成树得到这些 \(1\) 边,就确定了生成树里的部分 \(1\) 边。

之后随便加 \(1\) 边直到加满 \(k\) 条,再加入 \(0\) 边使其成为生成树即可。

回忆代码
//#include<bits/stdc++.h>
#include<algorithm> 
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
#include<unordered_set>
using namespace std;
constexpr const int N=2e5,M=2e5;
struct edge{
	int u,v,w,id;
}g[M+1];
int n,m,k;
struct dsu{
	int f[N+1],size[N+1];
	
	int find(int x){
		if(f[x]!=x){
			return f[x]=find(f[x]);
		}
		return x;
	}
	void merge(int x,int y){
		x=find(x),y=find(y);
		if(size[x]<size[y]){
			f[x]=y;
			size[y]+=size[x];
		}else{
			f[y]=x;
			size[y]+=size[x];
		}
	}
	void build(int n){
		for(int i=1;i<=n;i++){
			f[i]=i;
		}
	}
}dsu;
vector<int> Kruskal1(){
	sort(g+1,g+m+1,[](edge a,edge b){
		return a.w<b.w;
	});
	dsu.build(n);
	vector<int>ans;
	for(int i=1;i<=m;i++){
		auto [u,v,w,id]=g[i];
		if(dsu.find(u)==dsu.find(v)){
			continue;
		}
		dsu.merge(u,v);
		if(w){
			ans.push_back(id);
		}
	}
	return ans;
}
void Kruskal2(vector<int>&ans){
	sort(g+1,g+m+1,[](edge a,edge b){
		return a.w>b.w;
	});
	dsu.build(n);
	unordered_set<int>s;
	for(int i:ans){
		s.insert(i);
	}
	for(int i=1;i<=m;i++){
		auto [u,v,w,id]=g[i];
		if(s.count(id)){
			dsu.merge(u,v);
		}
	}
	k-=ans.size();
	if(k<0){
		ans={-1};
	}
	for(int i=1;i<=m;i++){
		auto [u,v,w,id]=g[i];
		if(dsu.find(u)==dsu.find(v)){
			continue;
		}
		if(w){
			if(k>0){
				k--;
				dsu.merge(u,v);
				ans.push_back(id);
			}
		}else{
			dsu.merge(u,v);
			ans.push_back(id);
		}
	}
	if(k!=0){
		ans={-1};
	}
}
int main(){
	/*freopen("test.in","r",stdin);
	freopen("test.out","w",stdout);*/
	
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	
	int T;
	cin>>T;
	while(T--){
		cin>>n>>m>>k;
		for(int i=1;i<=m;i++){
			cin>>g[i].u>>g[i].v>>g[i].w;
			g[i].id=i;
		}
		vector<int>ans=Kruskal1();
		Kruskal2(ans);
		for(int i:ans){
			cout<<i<<' ';
		}
		cout<<'\n';
	}
	
	cout.flush(); 
	
	/*fclose(stdin);
	fclose(stdout);*/
	return 0;
}

D

发现交换 \(i,j\) 的贡献为 \(\vert i-j\vert\),因此等价于两两交换的贡献。

要把 \(a_i\) 换到 \(i\) 的位置,操作次数为 \(\vert a_i-i\vert\)。每个点都会计算两次贡献,所以最终答案为:

\[\dfrac12\sum_{i=1}^n\vert a_i-i\vert \]

回忆代码
//#include<bits/stdc++.h>
#include<algorithm> 
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
using namespace std;
typedef long long ll;
constexpr const int N=5e5;
int n,a[N+1];
int main(){
	/*freopen("test.in","r",stdin);
	freopen("test.out","w",stdout);*/
	
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	
	cin>>n;
	ll ans=0;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		if(a[i]!=i){
			ans+=abs(a[i]-i);
		}
	}
	ans/=2;
	cout<<ans<<'\n';
	
	cout.flush(); 
	
	/*fclose(stdin);
	fclose(stdout);*/
	return 0;
}

E

设逆序对个数为 \(\operatorname{inv}(a)\),则答案为:

\[\sum_{i=1}^n\vert a_i-i\vert-\operatorname{inv}(a) \]

不会证

赛后代码
//#include<bits/stdc++.h>
#include<algorithm> 
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
using namespace std;
typedef long long ll;
constexpr const int N=5e5;
int n,a[N+1];
struct bit{
	int t[N+1];
	
	int lowbit(int x){
		return x&-x;
	}
	void add(int x,int k){
		while(x){
			t[x]+=k;
			x-=lowbit(x);
		}
	}
	int query(int x){
		int ans=0;
		while(x<=N){
			ans+=t[x];
			x+=lowbit(x);
		}
		return ans;
	}
}t;
int main(){
	/*freopen("test.in","r",stdin);
	freopen("test.out","w",stdout);*/
	
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	
	cin>>n;
	ll ans=0;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		if(a[i]!=i){
			ans+=abs(a[i]-i);
		}
	}
	for(int i=1;i<=n;i++){
		ans-=t.query(a[i]);
		t.add(a[i],1);
	}
	cout<<ans<<'\n';
	
	cout.flush(); 
	
	/*fclose(stdin);
	fclose(stdout);*/
	return 0;
}
posted @ 2026-07-20 20:23  TH911  阅读(7)  评论(0)    收藏  举报