题目:
解法:
解法一:(暴力求解法,70分)
暴力求解,就不给解释了,想看的稍微看一看即可。
#include <iostream>
using namespace std;
int max(int a[],int n) {
int x=0;
for(int j=0; j<n; j++) {
if(a[j]>=x) x=a[j];
}
return x;
}
bool quanling(int a[],int n) {
for(int i=0; i<n; i++) {
if(a[i]!=0) return false;
}
return true;
}
int main() {
int n;
cin>>n;
int a[n];
for(int i=0; i<n; i++) cin>>a[i];
int Max=max(a,n);
if(quanling(a,n)) {
cout<<0;
} else {
int count=0;
for(int p=1; p<=Max; p++) {
int temp=0;
for(int j=0; j<n-1; j++) {
if(j>=1) {
if(a[j]<p&&a[j+1]>=p) temp++;
else if(a[j]<p&&a[j+1]<p) continue;
else if(a[j]>=p&&a[j+1]<p) continue;
else if(a[j]>=p&&a[j+1]>=p) continue;
} else {
if(a[j]<p&&a[j+1]<p) continue;
else if(a[j]<p&&a[j+1]>=p) temp++;
else if(a[j]>=p) temp++;
}
}
if(temp>=count) count=temp;
}
cout<<count;
}
return 0;
}
解法二:(索引法,100分)
首先要找到一个向量,这个向量可以存储数组a中值的位置。即向量v[i]中存储的便是i在数组a中的位置。此时向量v可以看成数组a中每个值的索引。然后还要找到一个数组,此数组与数组a的值一一对应用作标记,即a[i]的值一旦被置为0,此数组[i]则被置为1.
开始时,要在数组a前后两端置0,并且对标记数组进行初始化。程序中有一last(上一次划分的段数)。取p为0到maxa(数组a的最大值),每个p则代表小于等于p的值置0。找到值为p的位置将标记数组记为1,当此位置左右均已置为0时划分段树减一,当此位置左右均不为0时则划分段加一。然后对目前结果,上一次划分段数last以及此次划分段数取最大值记为目前结果。最后将此次划分段数记为上一次划分段数last。
#include <iostream>
#include <string.h>
#include <vector>
using namespace std;
const int N = 500000;
const int M = 10000;
int a, book[N + 2];
vector <int> v[M + 1];
int main() { //索引法
int n, maxa = 0;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a;
maxa = max(maxa, a);
v[a].push_back(i); //v[a]中存储的是a在数组a中的位置
}
int ans = 0; //结果,最大段数
if (v[0].size() != n) { //如果数组a并非全0
memset(book, 0, sizeof book); //将book数组全部置零
book[0] = book[n + 1] = 1;//数组两端已经置零则被标记为1
int last = 1;
for (int p = 0; p <= maxa; p++) {
if (v[p].size() != 0) {
int tem = last;
for (int i = 0; i < (int)v[p].size(); i++) {
book[v[p][i]] = 1;
if (book[v[p][i] - 1] && book[v[p][i] + 1]) tem--;
else if (book[v[p][i] - 1] == 0 && book[v[p][i] + 1] == 0) tem++;
}
ans = max(ans, max(last, tem));
last = tem;
}
}
}
//数组a全0
cout << ans;
return 0;
}
顺手给出一个关于vector的网址:
解法三:(差分法,100分)
用差分法可以借助岛屿情况来分析。p足够大,所有的数(岛屿)被海水淹没,只有0个岛屿(划分段)。当海平面逐渐下降,岛屿数量出现变化。每当出现一个凸峰,岛屿数加一,每当出现一个凹谷,原本相邻的两个岛屿就被这个凹谷连在了一起,岛屿数减一。
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
const int N=500000;
const int M=10000;
int a[N+2],d[M+1];
int main() { //差分法
int n;
cin>>n;
for(int i=1; i<=n; i++) cin>>a[i];
a[0]=a[n+1]=0;
n=unique(a,a+n+2)-a-1; //最后一位坐标
memset(d,0,sizeof d);
for(int i=1; i<n; i++) {
if(a[i-1]<a[i]&&a[i]>a[i+1]) d[a[i]]++;
else if(a[i-1]>a[i]&&a[i]<a[i+1]) d[a[i]]--;
}
int ans=0,sum=0;
for(int i=M; i>=1; i--) {
sum+=d[i];
ans=max(ans,sum);
}
cout<<ans;
return 0;
}
总的来说,差分法就是先消去相邻的重复元素,再从unique后的数组第一位到最后一位,依次比较数字与相邻数的大小,并对d操作。(解释一下下:如果此时是从d[i]+d[i+1]+........ 则表示海平面为i时的岛屿数量,即p=i时的划分段数。)
这里说明一下unique,unique()函数是用来去除相邻重复的元素,返回的结果为去除相邻重复元素后的数组(将去除相邻元素后的数组放在新数组的前面部分,新数组的后面部分保持不变)
放个代码解释一下:
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int main() {
int n;
cin>>n;
int a[n];
for(int i=0; i<n; i++) cin>>a[i];
cout<<"原数组:"<<endl;
for(int i=0; i<n; i++) cout<<a[i]<<" ";
unique(a,a+n);
cout<<endl<<"unique后的数组:"<<endl;
for(int i=0; i<n; i++) cout<<a[i]<<" ";
cout<<endl;
cout<<"unique后的数组长度"<<(unique(a,a+n)-a); //unique(a,a+n)-a为求数组长度
return 0;
}
运行情况:
还有一特殊情况(本人认为unique后数组最后几位0合归为一位):