Codeforces Round #580 (Rated for Div.1+Div.2) 包含Div.2前4题题解

1206A - Choose Two Numbers

题意:有两个集合 A A A, B B B。给出它们当中的元素,让你求两个数 x , y x,y x,y,使得 x ∈ A , y ∈ B x \in A, y \in B xA,yB x + y ∉ A , x + y ∉ B x+y \notin A, x+y \notin B x+y/A,x+y/B

思路:用一个bool数组记录一下就可以了。

#include <bits/stdc++.h>
using namespace std;
int n,m,a[105],b[105];
bool p[405];
int main(){
	cin>>n;
	for(int i=1;i<=n;i++)	cin>>a[i],p[a[i]]=1;
	cin>>m;
	for(int i=1;i<=m;i++)	cin>>b[i],p[b[i]]=1;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(!p[a[i]+b[j]]){
				cout<<a[i]<<" "<<b[j]<<endl;
				return 0;
			}
		}
	}
	return 0;
}

也可以直接输出它们的最大值。

#include <bits/stdc++.h>
using namespace std;
int n,m,a[105],b[105],mx1,mx2;
int main(){
	cin>>n;for(int i=1;i<=n;i++)	cin>>a[i];
	cin>>m;for(int i=1;i<=m;i++)	cin>>b[i];
	cout<<*max_element(a+1,a+1+n)<<" "<<*max_element(b+1,b+1+m)<<endl;
}

1206B - Make Product Equal One

题意:有 n n n个数,每一次操作可以选择任意一个元素并将其 + 1 +1 +1 − 1 -1 1,问最少经过多少次操作才能使所有数的乘积为 1 1 1

思路:贪心,每个数优先选择变成距离 − 1 -1 1 1 1 1中距离自己近的,然后统计 1 1 1的个数,如果是奇数将代价最小的 − 1 -1 1变为 1 1 1.注意,再上一步,答案不能直接 + 2 +2 +2 0 0 0要特殊处理。

#include <bits/stdc++.h>
using namespace std;
#define int long long
int n,a[100005],cnt,ans;
signed main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		int dist1=abs(-1-a[i]);
		int dist2=abs(1-a[i]);
		if(dist1<dist2){
			cnt++;
			ans+=dist1;
		}
		else{
			ans+=dist2;
		}
	}
	if(cnt%2==0){
		cout<<ans<<endl;
	}
	else{
		int mn=LLONG_MAX;
		for(int i=1;i<=n;i++){
			int dist1=abs(-1-a[i]);
			int dist2=abs(1-a[i]);
			if(dist1<=dist2){
				mn=min(mn,dist2-dist1);
			}
		}
		cout<<ans+mn<<endl;
	}
	return 0;
}

1205A - Almost Equal

题意:给你一个 n n n,构造一个长度为 2 n 2n 2n的环,有 1 1 1 2 n 2n 2n组成,使环上每 n n n个连续的点的记录下来。其中这些数要求只有2个数字构成,并且这两个数必须连续。问是否能满足要求并给出方案。

思路:由于这个长度为 2 n 2n 2n的环和为 S = n ( 2 n + 1 ) S=n(2n+1) S=n(2n+1),因此 S S S是偶数时,无解。当 S S S是奇数时,有解。

考虑如何构造,我们设答案数组为 a n s ans ans,那么我们先令 a n s 1 = 1 ans_1=1 ans1=1 a n s n + 1 = 2 ans_{n+1}=2 ansn+1=2,然后每一次,我们进行如下操作:

第一步: a n s 2 = 3 , a n s n + 2 = 4 , a n s n + 3 = 5 , a n s 3 = 6 ans_2=3,ans_{n+2}=4,ans_{n+3}=5,ans{3}=6 ans2=3,ansn+2=4,ansn+3=5,ans3=6

第二步: a n s 4 = 7 , a n s n + 4 = 8 , a n s n + 5 = 9 , a n s 5 = 10 ans_4=7,ans_{n+4}=8,ans_{n+5}=9,ans{5}=10 ans4=7,ansn+4=8,ansn+5=9,ans5=10

等等,以此类推。

时间复杂度 O ( n ) O(n) O(n)

#include <bits/stdc++.h>
using namespace std;
#define int long long
int n,a[200005],cnt=0;
signed main(){
	cin>>n;
	if(n%2==0)	return puts("NO"),0;
	puts("YES");
	for(int i=n,j=2*n,k=2*n;i>0;){
		a[i]=k;a[j]=k-1;
		if(i-1>0){
			a[j-1]=k-2;a[i-1]=k-3;
		}
		i-=2;j-=2;k-=4;
	}
	for(int i=1;i<=2*n;i++)	cout<<a[i]<<" ";
	return 0;
}

1205B - Shortest Cycle

题意:有 n n n个数 a 1 , a 2 , a 3 , … , a n a_1,a_2,a_3,\dots,a_n a1,a2,a3,,an。已知如果两个数 a i , a j ( i ≠ j ) a_i,a_j (i \neq j) ai,aj(i̸=j)满足 a i   a n d   a j ≠ 0 a_i\ and\ a_j \neq 0 ai and aj̸=0(其中 a n d and and操作为按位与操作),那么在 i i i号节点与 j j j号节点间连一条边,求所构成的图的最小环的长度。

思路:首先,我们明白,这张图要么没有环,要么最小环的长度大于等于 3 3 3,因此,对于二进制下的每一位,只要有一位在 3 3 3个及以上个数的二进制表示下为 1 1 1,那么答案一定为 3 3 3

因为每个数都小于 1 0 18 10^{18} 1018,因此每个数最多有 60 60 60位,因此如果有超过 120 120 120个非零数字,那么必定有一位在 3 3 3个及以上个数的二进制表示下为 1 1 1

考虑没有任何一位在 3 3 3个及以上个数的二进制表示下为 1 1 1的情况,我们暴力连边,然后跑 F l o y d Floyd Floyd求最小环。因为最大只有 120 120 120个非零数字,所以时间复杂度最大为 O ( 12 0 3 ) O(120^3) O(1203)

总的时间复杂度 O ( n   l o g 1 0 18 + 12 0 3 ) O(n\ log 10^{18}+120^3) O(n log1018+1203)

#include <bits/stdc++.h>
using namespace std;
#define int long long
int n,a[100005],b[100005],dist[130][130],s[130][130],ans=LLONG_MAX,cnt;
signed main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		if(a[i]!=0)		b[++cnt]=a[i];
	}
	for(int i=1;i<=60;i++){
		int cnt=0;
		for(int j=1;j<=n;j++){
			if(a[j]>>(i-1)&1){
				cnt++;
			}
		}
		if(cnt>=3){
			puts("3");
			return 0;
		}
	}
	for(int i=1;i<=cnt;i++)
		for(int j=1;j<=cnt;j++){
			if(i!=j&&((b[i]&b[j])!=0))		s[i][j]=1,dist[i][j]=1;
			else							dist[i][j]=s[i][j]=0x3f3f3f3f;
		}
	for(int k=1;k<=cnt;k++){
		for(int i=1;i<k;i++)
			for(int j=i+1;j<k;j++)
				ans=min(dist[i][j]+s[i][k]+s[k][j],ans);
		for(int i=1;i<=cnt;i++)
			for(int j=1;j<=cnt;j++)
				dist[i][j]=min(dist[i][k]+dist[k][j],dist[i][j]);
	}
	cout<<((ans>=0x3f3f3f3f)?-1:ans)<<endl;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值