CF Global Round 20

CF-GR20

image
半夜思混乱还硬打3h的Global Round 的下场。。。

C

在输入n之前先给mn赋值n+1,然后样例n是不降的所以没发现,然后在WA2中迷茫。。。

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int n,a[N];
void work(){
	cin>>n;
	int mn=n+1,mx=0;
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i=1;i<n;i++) if(a[i]==a[i+1]){
		//cout<<"i="<<i<<endl;
		mn=min(mn,i);
		mx=max(mx,i+1);
	}
	//cout<<mn<<" "<<mx<<endl;
	if(!mx || mn+1==mx){
		puts("0");
	}
	else cout<<max(1,mx-mn-2)<<endl;
}
int main()
{
	//srand(time(0));
	//freopen("1.in","r",stdin);
	//freopen("1.out","w",stdout);
	int T; cin>>T; while(T--) work();
	return 0;
}
/*
1
4
2 1 1 2
*/

D

原本想了半天没什么思路,做了F1之后回来看,想到可以考虑如何把B
变成A,从后往前扫,遇到B中和上一个位置相同的就可以往前换。但当时以为要换到A中对应的那些位置中的一个,然而如果前面还有换其它的,就会改变它的位置。所以应该先把这些可以往前换的存下来,然后对于每一个位置,如果B与A不同,就拿存下来的那些换上去,如果没有就是无解。

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int n,a[N],b[N],c[N];
void work(){
	cin>>n;
	for(int i=1;i<=n;i++) scanf("%d",&a[i]),c[i]=0;
	for(int i=1;i<=n;i++) scanf("%d",&b[i]);
	for(int i=n,j=n;i;i--){
		while(j && j<n && b[j]==b[j+1]){
			c[b[j]]++;
			j--;
		}
		if(j && b[j]==a[i]) j--;
		else if(c[a[i]]) c[a[i]]--;
		else{
			puts("NO");
			return;
		}
	}
	puts("YES");
}
int main()
{
	//srand(time(0));
	//freopen("1.in","r",stdin);
	//freopen("1.out","w",stdout);
	int T; cin>>T; while(T--) work();
	return 0;
}

F1

如果已经确定一个排列置换,那么答案就是n-环数,又发现如果一个环有两个颜色相同的位置,那么交换这两个位置的目标就可以把这个环分成两个,所以最少会有\(max_{cnt}\)个环(记为x),又发现可以构造出这些环,答案最大即为n-x。

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int n,a[N],p[N];
int f[N];
vector<int>h[N];
bool cmp(vector<int>a,vector<int>b){
	return (int)a.size()>(int)b.size();
}
void work(){
	cin>>n;
	for(int i=1;i<=n;i++) scanf("%d",&a[i]),f[i]=0,h[i].clear();
	int m=0;
	for(int i=1;i<=n;i++){
		if(!f[a[i]]) p[++m]=i,f[a[i]]=m;
		int t=f[a[i]];
		h[t].push_back(i);
	}
	sort(h+1,h+m+1,cmp);
	/*
	for(int i=1;i<=m;i++){
		cout<<i<<" "<<p[i]<<endl;
		for(int j=0;j<h[i].size();j++) cout<<h[i][j]<<" "; puts("");
	}
	*/
	for(int i=0;i<(int)h[1].size();i++){
		int t=1;
		while(t<m && h[t+1].size()>i) t++;
		for(int j=1;j<t;j++) swap(a[h[j][i]],a[h[j+1][i]]);
	}
	for(int i=1;i<=n;i++) printf("%d ",a[i]);
	puts("");
}
int main()
{
	//srand(time(0));
	//freopen("1.in","r",stdin);
	//freopen("1.out","w",stdout);
	int T; cin>>T; while(T--) work();
	return 0;
}

F2

WA等价于存在一种安排,使得环数>x。然后发现这又等价于是否存在一个不经过出现次数最大颜色的位置的环(必要性显然,充分性即把这个环去掉,对剩下的重新安排,用F1的构造)。(想到这里的时候还是觉得这题很优美的)

然后,,,想了半天怎么判断有没有这样的环,一直在考虑一边bfs一边确定如何安排,用数据结构维护贪心什么的,没想出什么靠谱的做法。。。

但只要把每种颜色看成一个点,在颜色之间连遍,就相当于直接判断一个可能包含重边自环的有向图是否有环了!!!

(这题解就是在嘲笑我,我前面都想到了你告诉我这???)
image

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int n,a[N],b[N],c[N],p;
vector<int>h[N];
bool vs[N],iq[N],ans;
void dfs(int x){
	//cout<<"dfs:"<<x<<endl;
	vs[x]=iq[x]=1;
	int z=h[x].size();
	for(int i=0;i<z;i++){
		int y=h[x][i];
		if(y==p) continue;
	//	cout<<"y="<<y<<endl;
		if(iq[y]){
			ans=1; return;
		}
		else if(!vs[y]) dfs(y);
	}
	iq[x]=0;
}
void work(){
	cin>>n;
	for(int i=1;i<=n;i++) scanf("%d",&a[i]),c[a[i]]++;
	for(int i=1;i<=n;i++) scanf("%d",&b[i]);
	for(int i=1;i<=n;i++) h[a[i]].push_back(b[i]);
	p=0;
	for(int i=1;i<=n;i++) if(c[i]>c[p]) p=i;
	//cout<<"p="<<p<<endl;
	ans=0;
	for(int i=1;i<=n;i++) if(i!=p && !vs[i]) dfs(i);
	if(ans) puts("WA");
	else puts("AC");
	for(int i=1;i<=n;i++) h[i].clear(),vs[i]=c[i]=iq[i]=0;
	//!!! even if you assume that iq do not need to be cleared, you'd better clear all arrays to avoid errors!!!
}
int main()
{
	//srand(time(0));
	//freopen("1.in","r",stdin);
	//freopen("1.out","w",stdout);
	int T; cin>>T; while(T--) work();
	return 0;
}
posted @ 2022-04-27 20:48  sz[sz]  阅读(60)  评论(0编辑  收藏  举报