Codeforces Round 1040 (Div. 2)(补题)

文章目录

  • 前言
  • [A.Submission is All You Need](#A.Submission is All You Need)
  • [B. Pathless](#B. Pathless)
  • [C.Double Perspective](#C.Double Perspective)
  • [D.Stay or Mirror](#D.Stay or Mirror)

前言

又被卡在第二题了,当时脑子跟犯糊涂似的,B题越理越乱,导致比赛结束,还在想着题,彻夜难眠!


A.Submission is All You Need

Submission is All You Need

题目大意:

操作:

思路:只需要统计0的个数就行了,有多少个0就加上多少个1

由于mex的特性,以及操作时的特点,只要把0变成1就行,

代码:

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define ll long long
#define endl '\n'
#define fi first
#define se second 
#define pii pair<ll,ll>
const ll N=1e6+10;
ll s[N];
ll sum[N];
void slove()
{
	ll n;
	cin>>n;
	ll f=0;
	for(ll i=1;i<=n;i++)
	{
		cin>>s[i];
		sum[i]=s[i]+sum[i-1];
		if(s[i]==0)
		f++;
	}
	cout<<sum[n]+f<<endl;
}
signed main()
{
	IOS;
	ll t=1;
	cin>>t;
	while(t--)
	slove();
	return 0;
}

B. Pathless

Pathless

思路;

对于这一题是有规律的

如果a1,a2,...,an的和sum

1.如果sum>s;

则一定不会满足条件,这时只需要按原数组输出就行

2.sum==s

这种是一定会满足的直接输出-1;

3.s>sum

如果s-sum=1,可以通过先0后2再1的顺序输出

这样可以使得往返之后的额外增加的数,不管如何都不会凑成1

如果大于1,这一种不管如何排列,总会找到相邻的数进行往返,以此来凑齐多出的数

因为相邻数对的和可以通过线性组合覆盖所有大于1的数

代码:

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define ll long long
#define endl '\n'
#define fi first
#define se second 
#define pii pair<ll,ll>
const ll N=1e6+10;
ll s1[N];
void slove()
{
	ll n,s;
	cin>>n>>s;
	ll sum=0;
	ll a1=0,b1=0,c1=0;
	for(ll i=1;i<=n;i++)
	{
		cin>>s1[i];
		if(s1[i]==0)
		a1++;
		else if(s1[i]==1)
		b1++;
		else
		c1++;
		sum+=s1[i];
	}
	if(sum>s)
	{
		for(ll i=1;i<=n;i++)
		cout<<s1[i]<<" ";
		cout<<endl;
	}
	else
	{
		if(sum==s)
		{
		cout<<-1<<endl;
		}
		else
		{
		s=s-sum;
		if(s==1)
		{
			for(ll i=1;i<=a1;i++)
			cout<<0<<" ";
			for(ll i=1;i<=c1;i++)
			cout<<2<<" ";
			for(ll i=1;i<=b1;i++)
			cout<<1<<" ";
			cout<<endl;
			return ;
		}
			cout<<-1<<endl;
		}
		}
}
signed main()
{
	IOS;
	ll t=1;
	cin>>t;
	while(t--)
	slove();
	return 0;
}

C.Double Perspective

Double Perspective

其中主要的意思就是

f(s)代表的是在数轴上两点之间距离之和

就比如(1,2)(2, 3)(3,4)其f(s)就是3;

而g(s)

则代表的是成环的长度,此时ai与bi是一条无向边

就比如(1,2)(2,4)(1,4)此时成环,即g(s)=3;

了解完这些之后就是然后找到f(s)-g(s)的最大值

其实很简单,只需要把成环的边去掉,则剩下的集合就是最大的

代码:

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define ll long long
#define endl '\n'
#define pii pair<ll,ll>
#define fi first
#define se second
const ll N=1e6+10;
ll k;
ll s[N];
ll h[N];
void in()//初始化
{
	for(ll i=1;i<=2*k;i++)
	{
		s[i]=i;
		h[i]=0;
	}
}
ll find(ll x)//查找根节点
{
	ll r=x;
	while(r!=s[r])
	r=s[r];
	ll i=x,j;
	while(i!=j)
	{
		j=s[i];
		s[i]=r;
		i=j;
	}
	return r;
}
void mset(ll l,ll r)//合并
{
	l=find(l);
	r=find(r);
	if(l==r)
	return ;
	if(h[l]<h[r])
	{
		s[l]=r;
	}
	else
	{
		if(h[l]==h[r])
		h[r]++;
		s[r]=l;
	}
	return ;
}
void slove()
{
	cin>>k;
	in();
	vector<ll> p;
	for(ll i=1;i<=k;i++)
	{
		ll l,r;
		cin>>l>>r;
		l=find(l);
		r=find(r);
		if(l!=r)//如果不成环,相当于把成环的跳过了
		{
			mset(l,r);
			p.push_back(i);
		}
	}
	cout<<p.size()<<endl;
	for(auto i:p)
	cout<<i<<" ";
	cout<<endl;
}
signed main()
{
	IOS;
	ll t=1;
	 cin>>t;
	while(t--)
	slove();
	return 0;
}

D.Stay or Mirror

Stay or Mirror

题目的意思就是寻找逆序对的,就是这个条件

通过这个操作
能否使逆序对最小化。

注意:

当然这一题利用的贪心策略:

对于每个元素 p [i],计算两种选择(保留原值或选择 2n-p [i])分别会产生的逆序数贡献,然后选择贡献较小的那个

对于数组中的每个元素 p [i],代码计算两个值:

l:在 p [i] 之前(j < i)且比 p [i] 大的元素数量

r:在 p [i] 之后(j > i)且比 p [i] 大的元素数量

为什么这样计算?

当选择保留 p [i] 时,它会与前面所有比它大的元素形成逆序对,贡献为 L

当选择 2n-p [i] 时,由于 2n-p [i] 的值较大(对于排列中的元素),它不会与前面的元素形成逆序对,而是会与后面比它小的元素形成逆序对。而后面比 p [i] 大的元素数量 R,恰好等于后面比 2n-p [i] 小的元素数量(因为 2n-p [i] 较大)

因此,对于每个元素,取 min (L, R) 作为它对总逆序数的最小贡献,累加后得到最终结果。

代码:

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define ll long long
#define endl '\n'
#define pii pair<ll,ll>
#define fi first
#define se second
const ll N=1e4+10;
ll s[N];
void slove()
{
	ll n;
	cin>>n;
	for(ll i=1;i<=n;i++)
	{
		cin>>s[i];
	}
	ll ans=0;
	for(ll i=1;i<=n;i++)
	{
		ll l=0,r=0;
		for(ll j=1;j<=i;j++)//保留是s[i];
		if(s[j]>s[i])l++;
		for(ll j=i+1;j<=n;j++)//选择2n-s[i];
		if(s[j]>s[i])r++;
		ans+=min(l,r);//取其贡献最小的累加到答案
	}
	cout<<ans<<endl;
}
signed main()
{
	IOS;
	ll t=1;
	 cin>>t;
	while(t--)
	slove();
	return 0;
}
相关推荐
朝朝又沐沐4 分钟前
算法竞赛阶段二-数据结构(40)数据结构栈的STL
开发语言·数据结构·c++·算法
Antonio91538 分钟前
【网络编程】WebSocket 实现简易Web多人聊天室
前端·网络·c++·websocket
清朝牢弟2 小时前
Ubuntu系统VScode实现opencv(c++)图像放缩与插值
c++·vscode·opencv·ubuntu·计算机视觉
呆瑜nuage2 小时前
list的使用和模拟
c++·list
好好先森&3 小时前
C语言:模块化编程
c语言·c++·windows
爱学习的小邓同学3 小时前
c++ --- priority_queue的使用以及简单实现
c++
清朝牢弟5 小时前
Ubuntu系统VScode实现opencv(c++)视频的处理与保存
c++·人工智能·vscode·opencv·ubuntu
oioihoii5 小时前
在macOS上使用VS Code和Clang配置C++开发环境
c++·macos·策略模式