该题我第一思路只能想到暴力,即直接枚举所有可能的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; }