Codeforces Round #759 div. 2 A-D题解

A: Life of a Flower

题意

有一朵初始高度为 1 1 1 的花,它第 i i i 天的成长状态如下:

  1. 如果第 i i i i − 1 i-1 i1 连续两天都没有浇水,它会枯死
  2. 如果第 i i i 天浇水(但是第 i − 1 i-1 i1 天未浇水),它会长高 1 c m 1cm 1cm
  3. 如果第 i i i i − 1 i-1 i1 连续两天都浇水,它会长高 5 c m 5cm 5cm
  4. 如果第 i i i 天没有浇水,它不会成长

现给出 n n n 天的浇水状况,求花的最终高度,若中途枯死则输出 − 1 -1 1

题解

根据题意模拟即可

参考代码

#include<bits/stdc++.h>
using namespace std;
 
template<class T>inline void read(T&x){
	x=0;
	char c=getchar(),last=' ';
	while(!isdigit(c))last=c,c=getchar();
	while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
	if(last=='-')x=-x;
}
 
const int MAXN=1e2+5;
int n;
int a[MAXN];
 
int main()
{
	int T;read(T);
	while(T--){
		read(n);
		int ans=1;
		for(int i=1;i<=n;i++){
			read(a[i]);
			if(ans==-1)continue;
			if(a[i]){
				if(a[i-1])ans+=5;
				else ans++;
			}
			else{
				if(i>1&&a[i-1]==0)ans=-1;
			}
		}
		cout<<ans<<'\n';
	}
	return 0;
}

B: Array Eversion

题意

给出一个长度为 n n n 的数组 a a a,定义一种操作如下:

  1. x = a n x=a_n x=an
  2. 将数组分类为两个部分,左部分包含 a i ≤ x a_i\le x aix 的元素,右部分包含 a i > x a_i>x ai>x 的元素,各部分内元素顺序与原数组顺序一致
  3. 将左右部分合并,即为操作后的新数组

可以证明在有限次操作后,数组将不会变化(即再进行操作得到的新数组不变)
求可以使得数组变为不变状态的最小操作次数

题解

Lemma1:当 a n ≥ a i ( 1 ≤ i ≤ n ) a_n\ge a_i(1\le i\le n) anai(1in) ,即 a n a_n an 为数组中最大元素时,数组不会被操作改变

Lemma2:一次操作后, i i i 最大的 a i > x ( a n ) a_i>x(a_n) ai>x(an) 会成为新的 a n a_n an

n n n ~ 1 1 1 扫描一次数组,每次扫到一个 a i > a n a_i>a_n ai>an 时将 a i a_i ai 替换为新的 a n a_n an ,操作数+1即可

参考代码

#include<bits/stdc++.h>
using namespace std;

template<class T>inline void read(T&x){
	x=0;
	char c=getchar(),last=' ';
	while(!isdigit(c))last=c,c=getchar();
	while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
	if(last=='-')x=-x;
}

const int MAXN=2e5+5;
int n;
int a[MAXN];

int main()
{
	int T;read(T);
	while(T--){
		read(n);
		for(int i=1;i<=n;i++)read(a[i]);
		int ans=0;
		for(int i=n-1,last=a[n];i>=1;i--){
			if(a[i]>last){
				ans++;
				last=a[i];
			}
		}
		cout<<ans<<'\n';
	}
	return 0;
}

C: Minimize Distance

题意

在数轴上有 n n n 个仓库,第 i i i 个仓库位于 x i x_i xi
在原点上有 n n n 件货物(没有货物时要回原点拿),一位商人从原点出发,他同时最多可以带 k k k 件货物,当他经过一个仓库时,他就可以将一件带着的货物放入仓库中
求将 n n n 件货物放入 n n n 个仓库中,商人所需行走的最短路程(注意最终完成任务时商人不必回到原点)

题解

首先我们将正负数分开处理(因为在原点的不同方向上)
对于同一方向上的任务,我们采用贪心,每次送最远的 k k k 个仓库(若不足则将该方向上全部送完),代价是所送仓库中 m a x ( ∣ x i ∣ ) × 2 max(|x_i|)\times 2 max(xi)×2 (因为要走来回所以要乘 2 2 2 )
最后减去所有仓库中 m a x ( ∣ x i ∣ ) max(|x_i|) max(xi) 即可(显然最后停留在这个点不回原点可以减少最多的代价)

参考代码

#include<bits/stdc++.h>
using namespace std;

template<class T>inline void read(T&x){
	x=0;
	char c=getchar(),last=' ';
	while(!isdigit(c))last=c,c=getchar();
	while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
	if(last=='-')x=-x;
}

const int MAXN=2e5+5;
int n,k;
int ca,cb;
long long a[MAXN],b[MAXN];
long long ans;

int main()
{
	int T;read(T);
	while(T--){
		read(n),read(k);
		ca=cb=1;
		for(int i=1,x;i<=n;i++){
			read(x);
			if(x>0)a[ca++]=x;
			else b[cb++]=x;
		}ca--,cb--;
		sort(a+1,a+ca+1);
		sort(b+1,b+cb+1,greater<int>());
		ans=-max(a[ca],-b[cb]);
		for(int i=ca;i>=1;i-=k)ans+=2*a[i];
		for(int i=cb;i>=1;i-=k)ans-=2*b[i];
		cout<<ans<<'\n';
	}
	return 0;
}

D: Yet Another Sorting Problem

题意

给定一个长度为 n n n 的数组 a a a ,我们有以下交换规则:

  1. 选定 3 3 3 个互不相同的位置 i , j , k i,j,k i,j,k
  2. a i , a j , a k a_i,a_j,a_k ai,aj,ak 分别变为 a j , a k , a i a_j,a_k,a_i aj,ak,ai

问只使用这种交换方式,能否使得整个数组变为不降的

题解

Lemma1:(参考样例 3 3 3 )如果有两个元素相同,我们定然可以排序使得整个数组不降
证明:
令四个元素为 a , a , x , y a,a,x,y a,a,x,y
先交换前 3 3 3 个元素,得 a , x , a , y a,x,a,y a,x,a,y
再交换后 3 3 3 个元素,得 a , a , y , x a,a,y,x a,a,y,x
显然,我们在不调整其他元素的条件下实现了 x , y x,y x,y 两个元素的互换
既然可以实现任意两个元素的交换,那么排序显然可行

Lemma2:排列的奇偶性始终不变
证明:
不妨令 x , y , z ( x < y < z ) x,y,z(x<y<z) x,y,z(x<y<z) 为相邻的三个元素,此时交换这三者不会对其他的元素的逆序对造成干扰,
则全排列交换结果,有:

  1. x , y , z x,y,z x,y,z(逆序数:0)
  2. y , z , x y,z,x y,z,x(逆序数:2)
  3. z , x , y z,x,y z,x,y(逆序数:2)
  4. x , z , y x,z,y x,z,y(逆序数:1)
  5. z , y , x z,y,x z,y,x(逆序数:3)
  6. y , x , z y,x,z y,x,z(逆序数:1)

其中 1 , 2 , 3 1,2,3 1,2,3 可以通过交换互相转化,且都为偶排列, 4 , 5 , 6 4,5,6 4,5,6 可以通过交换互相转化,且都为奇排列,显然奇偶性不变
扩展到不相邻的三个元素 a i , a j , a k a_i,a_j,a_k ai,aj,ak ,我们可以通过若干次相邻交换使得他们相邻并且不改变其他元素的相对顺序,然后对他们相邻交换,再还原其他元素到原位置即可,由此可见对于一般性的交换也可以等价到若干次相邻交换,即奇偶性也不变

那么如果我们的原数组是一个偶排列(即奇偶性与自然排列相同),那么一定存在一种方法通过相邻交换消除逆序对还原成为自然排列(即逆序数变为 0 0 0 );反之若为奇排列,则一定无解(最终逆序数一定为奇数,不可能为 0 0 0 )

综上所述,我们可以先判数组中是否有重复元素,有则直接输出 Y E S YES YES ,否则检查排列奇偶性即可(我使用了归并排序来求逆序数)

参考代码

#include<bits/stdc++.h>
using namespace std;

template<class T>inline void read(T&x){
	x=0;
	char c=getchar(),last=' ';
	while(!isdigit(c))last=c,c=getchar();
	while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
	if(last=='-')x=-x;
}

const int MAXN=5e5+5;
int n;
int a[MAXN],tmp[MAXN];
bitset<MAXN>vis;

long long merge_sort(int l,int r){
	if(l>=r)return 0;
	int mid=l+r>>1;
	long long ret=merge_sort(l,mid)+merge_sort(mid+1,r);
	int i=l,j=mid+1,k=l;
	while(i<=mid&&j<=r){
		if(a[i]<=a[j])tmp[k++]=a[i++];
		else{
			ret+=mid-i+1;
			tmp[k++]=a[j++];
		}
	}
	while(i<=mid)tmp[k++]=a[i++];
	while(j<=r)tmp[k++]=a[j++];
	for(int i=l;i<=r;i++)a[i]=tmp[i];
	return ret;
}


int main()
{
	int T;read(T);
	while(T--){
		read(n);
		for(int i=1;i<=n;i++)read(a[i]);
		vis.reset();
		int ok=0;
		for(int i=1;i<=n;i++){
			if(vis[a[i]])ok=1;
			vis[a[i]]=1;
		}
		if(ok)puts("YES");
		else puts(merge_sort(1,n)&1?"NO":"YES");
	}
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值