Codeforces Round #813 (Div. 2)

好久没打cf了,,,这个假期太摆烂了呜呜呜,应该会掉大分

(不知道为啥没rated,也没给我发消息啊???)

似乎是手速场,可惜跟不上节奏了

A. Wonderful Permutation

给出一个permutation和一个k,每次交换可以使得任意两数互换,使得前k个数和最小的做少操作次数是多少。

思路:前k个数之和最小肯定是1加到k,map维护一下,仅交换不在这个范围内的即可。

AC Code:

#include<bits/stdc++.h>

typedef long long ll;
const int N=1e5+5;
int t,n,k;
int a[N];
std::map<int,int>mp;

int main(){
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);
	std::cout.tie(0);
	std::cin>>t;
	while(t--){
		std::cin>>n>>k;
		mp.clear();
		for(int i=1;i<=k;i++){
			mp[i]++;
		}
		int ans=0;
		for(int i=1;i<=n;i++){
			std::cin>>a[i];
			if(i<=k&&!mp[a[i]]) ans++;
		}
		std::cout<<ans<<'\n';
	}
	return 0;
}

 B. Woeful Permutation

给出一个n,构造一个permutation,使得每个i和p[i]的最小公因数之和最大。

思路:首先某个数一定与相邻的数互质,满足这个条件可以使得最小公因数最大,那么最大化利用每个数的方法是交换相邻两数,注意奇数个数时首先从最后开始交换。

AC Code:

#include<bits/stdc++.h>

typedef long long ll;
const int N=1e5+5;
int t,n;
int ans[N];

int main(){
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);
	std::cout.tie(0);
	std::cin>>t;
	while(t--){
		std::cin>>n;
		for(int i=1;i<=n;i++){
			ans[i]=i;
		}
		if(n&1){
			for(int i=2;i<=n;i+=2){
				std::swap(ans[i],ans[i+1]);
			}
		}
		else{
			for(int i=1;i<=n;i+=2){
				std::swap(ans[i],ans[i+1]);
			}
		}
		for(int i=1;i<=n;i++){
			std::cout<<ans[i]<<" \n"[i==n];
		}
	}
	return 0;
}

 os:假期躺平,后果就是B题还会WA两次

C. Sort Zero

给出一个数组a,每次操作可以选择一个数x并使数组中所有值为x的元素变成0,最少需要几次操作使得数组非递减排列。

 思路:贪心即可。遇到递减的一对数,就把前面的都变为0,,注意标记前面变为0的数,后面不要重复操作了。

考虑贪心的可行性,只要有递减的一对数,想将其变成合法序列,必须前一个数变小,那只能是0,前面大于0的数也必须相应变为0,而后面等于该数的位置也会变成0,一系列也就只能全为0了。注意代码写法,map相互赋值是O(n)的。其实好像也不难想,,是我菜了

AC Code:

#include<bits/stdc++.h>

typedef long long ll;
const int N=1e5+5;
int t,n,ans;
int a[N];
std::map<int,int>mp;

int main(){
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);
	std::cout.tie(0);
	std::cin>>t;
	while(t--){
		std::cin>>n;
		ans=0;
		for(int i=1;i<=n;i++){
			std::cin>>a[i];
		}
		mp.clear();
		int pos=-1;
		if(a[1]) mp[a[1]]=1;
		for(int i=2;i<=n;i++){
			if(a[i]<a[i-1]){
				ans=mp.size();
				pos=i;
			}
			if(ans<mp.size()&&mp[a[i]]&&mp[a[i]]<pos){
				ans=mp.size();
			}
			if(!mp[a[i]]&&a[i]) mp[a[i]]=i;
		}
		std::cout<<ans<<'\n';
	}
	return 0;
}

os:还因为mapT了一发,寄

D. Empty Graph

给出一个数组a,有k次操作,每次操作可以令a数组中某个数变为x,n个点的无向图,l点到r点的距离是区间l到r在数组a中的最小值。问在图中最长边的值。

思路:学习大佬的思路首先有个结论是显然的,区间越长,最小值不会较大。这样要求最大的值,所以有三条路线是最优的:1、l->r;2、l->1->r(a数组中最小值在1~l中,且2*d[1,n]<d[l,r]);3、l->n->r(a数组中最小值在r~n中,且2*d[1,n]<d[l,r]),所以d[l,r]=min(d[1,n]*2,d[l,r]),答案就是min(d[1,n]*2,max(d[u,v]))。由于区间min的单调递减性,所以d[u,v]取最大的话,只要满足v=u+1就行了,也就是说只用判断相邻的是否满足条件就行了,考虑二分答案,注意最小值限制即可。

AC Code:

#include<bits/stdc++.h>

typedef long long ll;
const int N=1e5+5;
int t,n,k;
int a[N],b[N];

bool check(int x){
	int nk=k;
	for(int i=1;i<=n;i++){
		if(a[i]*2<x){
			b[i]=1e9;
			nk--;
			if(nk<0) return false;
		}
		else b[i]=a[i];
	}
	if(nk>=2) return true;
	for(int i=2;i<=n;i++){
		if(std::min(b[i],b[i-1])>=x) return true;
		if(std::max(b[i],b[i-1])>=x&&nk>=1) return true;
	}
	return false;
}

int main(){
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);
	std::cout.tie(0);
	std::cin>>t;
	while(t--){
		std::cin>>n>>k;
		for(int i=1;i<=n;i++){
			std::cin>>a[i];
		}
		int l=1,r=1e9;
		while(l<r){
			int mid=l+r+1>>1;
			if(check(mid)) l=mid;
			else r=mid-1;
		}
		std::cout<<l<<'\n';
	}
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值