Codeforces Round 967 (Div. 2) (A~D)

Codeforces Round 967 (Div. 2)

写在前面

div2一如既往打的很烂·····,赛时C题经常都是卡着,每次都是赛后才写出来,还是得多刷div2的题目······

A. Make All Equal

思路

签到题,找出最大值的个数,总数减去最大值个数即可

code

void solve(){
	map<int,int> m;
	int maxn=0;
	int n;cin >> n;
	for(int i=1;i<=n;++i){
		int x;cin >> x;
		m[x]++;
		maxn=max(maxn,m[x]);
	} 
	cout << n-maxn << endl;
	return ;
}

B. Generate Permutation

思路

考点:模拟+构造

假设排列是升序的,那么正序只需要操作一次,倒序就需要操作n次
那么正序和倒序所需要的操作数就为 n + 1 n+1 n+1
我们需要做的就是让正序和倒序操作数相同,很明显当n为偶数时,他们一定不可能实现

一个很明显的构造:先找出序列的中位数,将左右两边的数进行调换,调换完左边的数是倒着的,右边的数是正着的

好比一个序列1 2 3 4 5 6 7
颠倒完后为:7 6 5 1 2 3 4
正反的操作数都为4次

code

void solve(){
	int n;cin >> n;
	if(n==1){
		cout << 1 << endl;
		return ;
	} 
	if(n%2==0) cout << -1 << endl;
	else{
		for(int i=n;i>n/2+1;--i) cout << i << " ";
		for(int i=1;i<=n/2+1;++i) cout << i << " ";
		cout << endl;
	}
	return ;
}

C. Guess The Tree

思路

对于每次询问,它都会有两种情况

  • 程序给出的答案为 a a a
  • 程序给出的答案不为 a a a

对于第一种情况,显然我们已经找到了答案,直接将他们存到 a n s ans ans数组即可
对于第二种情况,我们可以让 a a a不断更新为程序给出的整数 x x x,直到程序给出的值为 a a a停止,将当前这两个数存入ans数组

code

void solve(){
	map<PII,int> m;
	int n;cin >> n;
    for(int i=2;i<=n;++i){
    	  int a=1,b=i;
    	  while(a!=b){
    	  cout << "? " << a << " " << b << endl;
    	  int x;cin >> x;
    	  if(x==a) break;
    	  a=x;
		}
        m[{a,b}]=1;    	
	}
	cout << "! " ;
	for(auto i : m){
		PII pa=i.fi;
		cout << pa.fi << " " << pa.se << " ";
	}
	cout << endl;
	return ;
}

D. Longest Max Min Subsequence

思路

考点:贪心

我们先不考虑-1的情况,就看这个序列最长的长度
显然,它最长的长度就为序列中不重复元素的总和

既然它要在奇数项的位置乘上-1,那么奇数项上的元素越大,乘完之后就越小
对于偶数项而言,自然是越小越好

从贪心的思想去考虑,每次奇数项都放最大值,偶数项都放最小值即可
我们可以开两个大根堆去维护每次取值的范围,最大值的根堆存的是正值,最小值的根堆存的是负值
每次取值都判断当前元素是否被取过以及当前的坐标是否比上一次取值的坐标大即可

code

const int N=1e6+5;
int a[N],ans[N],vis[N];
void solve(){
	unordered_map<int,int> m;
	priority_queue<PII> mx,mn;
	set<int> s;
	int n;cin >> n;
	for(int i=1;i<=n;++i){
		cin >> a[i];
		m[a[i]]++;
	}
	for(int i=1;i<=n;++i) vis[i]=0;
	int len=m.size();
	int cnt=1,pos=0;
	for(int i=1;i<=n;++i){
		m[a[i]]--;
		mn.push({-a[i],-i});
		mx.push({a[i],-i});
		if(m[a[i]]==0){
			while(!vis[a[i]]){
			   if(cnt & 1){
		   		    while (mx.size() && (vis[mx.top().first] || -mx.top().second <= pos)) mx.pop();
					if (mx.size()) {
						ans[cnt++]=mx.top().first;
						vis[mx.top().first]=1;
						pos =-mx.top().second;
						mx.pop();
					}
			   }
			   else{
				    while (mn.size() && (vis[-mn.top().first] || -mn.top().second <= pos)) mn.pop(); 
					if (mn.size()) {
						ans[cnt++]=(-mn.top().first);
						vis[-mn.top().first]=1;
						pos = -mn.top().second;
						mn.pop();
					}
			     }	
			}
		}
    }
	cout << len << endl;
	for(int i=1;i<=len;++i) cout << ans[i] << " ";
	cout << endl;
	return ;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值