CCF2021-9-2非零段划分
1.题意为将数组中的每一个数依次作为阈值,将数组中比此数小的都置为0,其余不变,然后数出此时非零段的个数(两个或两个以上不为0的数相邻算一段),最后记录每个数作为阈值时的非零段个数,输出个数最多的阈值。
2.题解(100分代码)
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int a[500005];
int cnt[10005]={0};
int main()
{
int n;
int i,j,sum=0,ans=0;
cin>>n;
for(i=1;i<=n;i++) cin>>a[i];
a[0]=0;
a[n+1]=0;
n=unique(a,a+n+2)-a;
for(i=1;i<n-1;i++)
{
if(a[i]>a[i-1]&&a[i]>a[i+1]) cnt[a[i]]++;
else if(a[i]<a[i-1]&&a[i]<a[i+1]) cnt[a[i]]--;
}
for(i=10000;i>1;i--)
{
sum+=cnt[i];
ans=max(ans,sum);
}
cout<<ans<<endl;
return 0;
}
3.讲解:
可以将此题理解为海平面的升降问题,当海水退去,先露出的都是最高的礁石,当海水慢慢退去,两块礁石底部之间的土地露出时,可以将这两块礁石看作一块陆地。在此背景下,海水的高度就是每个阈值数,随着海水的下降,露出的礁石数就是此阈值下非零段的个数。
每露出一个峰(大于左,大于右)总数便++,每露出一个谷(小于左小于右)便–,因为每露出一个谷,说两个峰已经合并成一块大陆,所以要减减,为了避免两个相邻的两个峰数(既然为峰,说明此时两数相等)重复计算,则需要使用unique
函数去重(使用前不用排序,因为峰相连说明相邻数相等),然后寻找峰和谷,进行加加和减减操作,此减减、加加操作意思是,在原有的非零段个数上进行操作,加加就是多出1段,减减就是合并少了1段,然后将每次操作后的数字记录下来,从大到小进行累加,每次求出最大值,最后再输出。