CCF-CSP 202109-2 非零段划分

 该题我第一思路只能想到暴力,即直接枚举所有可能的p,然后根据题意将所有小于p的元素变为0,再计算每次数组的非零段的数量即可

#include<iostream>
#include<climits>
#include<cstring>
#include<algorithm>
using namespace std;

int n;
int arr[500005];
int maxn=INT_MIN,minn=INT_MAX,ans;

int getNum(int *A){//计算数组A的非零段个数 
	//前后都为0的子数组为一个非零段
	int res=0;
	for(int i=0;i<=n+1;i++){
		if(A[i]==0){
			continue;
		}else{
			while(A[i]!=0){
				i++;
			}
			res++;
		}
	}
	return res;
}

int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>arr[i];
		maxn=max(maxn,arr[i]);
		minn=min(minn,arr[i]);
	}
	ans=getNum(arr);
	if(minn==0)minn=2;
	for(int p=minn;p<=maxn;p++){
		//枚举所有可能的p 
		int *temp=new int[500005];
		memcpy(temp,arr,sizeof(arr));
		//将<p的数变为0
		for(int i=1;i<=n;i++){
			if(temp[i]<p){
				temp[i]=0;
			}
		} 
		int notZero=getNum(temp);
		ans=max(ans,notZero);
		free(temp);
	}
	cout<<ans<<endl;
	return 0;
} 

思路2

参考自

(借助岛屿问题):

p足够大时,所有的岛都被海水淹没了,只有0个岛屿
海平面逐渐下降,岛屿数量开始变化
每当一个凸峰出现,岛屿数就会多一个;
每当一个凹谷出现,原本相邻的两个岛屿就被这个凹谷连在一起了,岛屿数减少一个
使用数组sub[],sub[i] 表示海平面下降到i时,岛屿数量的变化(此时小于i的数都变为0)
数组元素sub[i]中存储的就是该元素被替换为0时,划分数变化的差分值
在其前缀和(实际为后缀和)中求出最大值

简单来说就是取一个数组记录当p值取得该数组下标值时,岛屿数量的变化,例如存在这样的序列2 5 2,那么当p取得5时,就必然得到一个非零段,因此我们记录sub[ 5 ]+=1

此外例如存在这样的序列5 2 5,那么当p取得2时,本身可以分为两个岛屿的点现在反而相连了,因此我们记录sub[ 2 ]-=1
最后求后缀和即可

#include<iostream>
#include<algorithm>
using namespace std;

int n,ans=INT_MIN,beh=0;
int A[500005];
int sub[10005];//差分数组 

int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>A[i];
	}
	n=unique(A+1,A+n+1)-(A+1);//去除相邻重复元素同时得到去重后的长度
	A[n+1]=0;//需要对边界重新赋值!!
	for(int i=1;i<=n;i++){
		if(A[i]>A[i-1]&&A[i]>A[i+1]){//凸点 
			sub[A[i]]++;
		}else if(A[i]<A[i-1]&&A[i]<A[i+1]){//凹点 
			sub[A[i]]--;
		}
	} 
	for(int i=10001;i>=0;i--){//从后往前遍历避免得不到最大值,因为0的位置总为负数 
		beh+=sub[i];
		ans=max(ans,beh);
	}
	cout<<ans<<endl;
	return 0;
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZZZWWWFFF_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值