Codeforces Round 998 (Div. 3)

A

给了\(a_1,a_2,a_4,a_5\),求\(a_3\)使得满足斐波拉契数列的关系式的个数

solution:假设\(a_3\)满足一个关系,然后再去试其他关系式是否正确

B

给一个二维数组,同一行的数可以交换,寻找一种枚举顺序,使得每一列都按照这样的顺序取出来的数,全部都单调递增

如何确定顺序:

每一行都排序,我们一定要确保第一列都是单调递增的,否则后面的满足题意也没用,所以要排序

如何确定顺序是对的:

如果依次取出来的数都单调递增,那么同一行的数(排序后)一定满足,单调递增且公差为n(行数)

#include<bits/stdc++.h>
using namespace std;
int t;
int n,m;
const int maxn=2e3+10;
int a[maxn][maxn];
int b[maxn];
bool book[maxn];
int nt[maxn];
void solve(){
	cin>>n>>m;
	queue<int> ans;
	for(int i=1;i<=n;++i){
		for(int j=1;j<=m;++j) cin>>b[j];
		sort(b+1,b+1+m);
		for(int j=1;j<=m;++j) a[i][j]=b[j];
	}
	for(int i=1;i<=n;++i){
		int minn=1e5+10,p;
		for(int j=1;j<=n;++j){
			if(book[j]==0 && minn>a[j][1]){
				p=j;
				minn=a[j][1];
			}
		}
		book[p]=1;
		
		for(int j=1;j<m;++j)
			if(a[p][j]+n!=a[p][j+1]){
				puts("-1");
				return ;
			}
		ans.push(p);
	} 
	while(!ans.empty()){
		cout<<ans.front()<<" ";
		ans.pop();
	}
	cout<<"\n";
	
	
	return ;
	
}
int main(){
	cin>>t;
	while(t--){
		solve();
		memset(book,0,sizeof(book));
		
	}	
	return 0;
}

C

给定偶数长度的一组数,A,B轮流选一个数,如果和等于K,那么score+1

A想要减少score,B想要增加score

对于数组中的数,我们可以分成两类,一种可以和其他的数组成k,一种则不然

所以对于A,首先会选择不能构成k的数,此时B为了不减少可以构成k的数,也选择不能构成k的数
当第一类数选完了,A只能选择可以构成k的数,B此时要选择与A选的数相加等于k的数

这样满足题意

#include<bits/stdc++.h>
using namespace std;
int t;
int n,k;
const int maxn=2e5+10; 
int x[maxn];
void solve(){
	cin>>n>>k;
	for(int i=1;i<=n;++i) cin>>x[i];
	sort(x+1,x+1+n);
	int a=0;
	for(int i=1,j=n;i<j;++i){
		while(x[i]+x[j]>k && j>i){
			--j;
		}
		if(x[i]+x[j]==k && i!=j) a+=2,--j;
	}
	int b=n-a;
	if(b%2)		a-=1;
	cout<<a/2<<"\n";
	
}
int main(){
	cin>>t;
	while(t--){
		solve();
	}	
	return 0;
}


D

给了一个数组,可以进行这样的操作:减去相邻两个数的最小值
这样操作后是否可以使得数组单调递增(可以等于

显然如果在操作过程中\(a_i>a_{i+1}\),数组无论如何操作都会单调递增

所以模拟一遍操作过程即可

#include<bits/stdc++.h>
using namespace std;
int t;
int n,k;
const int maxn=2e5+10; 
int x[maxn];
void solve(){
	cin>>n;
	for(int i=1;i<=n;++i) cin>>x[i];
	for(int i=2;i<=n;++i){
		if(x[i]<x[i-1]) {
			puts("NO");
			return ;
		}
		else {
			x[i]-=x[i-1];
			x[i-1]=0; 
			if(x[i]>x[i+1] && i!=n){
				puts("NO");
				return ;
			}
		}
	} 
	puts("YES");
	return ;
	
}
int main(){
	cin>>t;
	while(t--){
		solve();
	}	
	return 0;
}

E

给出两个图F,G,可以任意删去,增加F中的边

是否经过操作后,使得F,G中的顶点之间,存在的连通性相同

我们只考虑连通性,不关心具体的边怎么实现,这时就可以用并查集来实现

  • 如果F中两点之间连通但G中不,所以删去一条边
  • 如果G中两点之间连通但F中不,所以增加一条边

先建立G图的连通性,再根据G图,再建立F图

#include<bits/stdc++.h>
 
using namespace std;
int n,m1,m2;
int t;
const int maxn=4e5+10;
 
int f1[maxn],f2[maxn];
struct node{
	int u,v;
}e1[maxn],e2[maxn];
int find1(int x){
	if(x!=f1[x])return f1[x]=find1(f1[x]);
	return x;
}
int find2(int x){
	if(x!=f2[x])return f2[x]=find2(f2[x]);
	return x;
}
void init(){
	cin>>n>>m1>>m2;	
	for(int i=1;i<=n;++i) f1[i]=f2[i]=i;
	for(int i=1;i<=m1;++i){
		cin>>e1[i].u>>e1[i].v;
	}	
	for(int i=1;i<=m2;++i) {
		cin>>e2[i].u>>e2[i].v;
		int u=find2(e2[i].u);
		int v=find2(e2[i].v);
		f2[u]=v;
	}
 
}
void solve(){
	init();
	int ans=0;
	for(int i=1;i<=m1;++i){
		int u=e1[i].u,v=e1[i].v;
		if(find2(u)!=find2(v))++ans;
		else f1[find1(u)]=find1(v);
	}
	for(int i=1;i<=m2;++i){
		int u=find1(e2[i].u),v=find1(e2[i].v);
		if(u!=v){
			++ans;
			f1[u]=v;
		}
	}
	cout<<ans<<endl;
}
int main(){
	cin>>t;
	while(t--){
		solve();		
	}
	return 0;
} 
posted @ 2025-01-23 21:34  归游  阅读(80)  评论(0)    收藏  举报