1.202109-1数组推导
根据题意知道 Bi = max{A1,A2,...,Ai} Bi一定是一个单调递增的序列,并且Ai <= Bi 由此可以确定数组A的sum的最大值就是数组B的和;而对于最小值,如果在B数组中 B[i] == B[i-1] 也就意味着 A[i]可以在此处无贡献则 A[i]最小为0;但若 B[i] > B[i-1] 那么 A[i] 只能等于B[i]。
代码如下:
#include <iostream>
using namespace std;
const int N = 100010;
int a[N];
int main()
{
int n;
scanf("%d",&n);
int ans_max = 0;
int ans_min = 0;
for(int i = 0;i < n;i++)
scanf("%d",&a[i]);
for(int i = 0;i < n;i++)
{
ans_max += a[i];
if(!i || a[i] > a[i-1])
ans_min += a[i];
}
printf("%d\n%d",ans_max,ans_min);
return 0;
}
2.202109-2非零段划分
非常容易想到的就是暴力枚举,把p从所有输入的最小值到最大值的每种情况都枚举一遍,然后找到最大值(想是好想,就是写起来不好写,虽然只有70分但是还是写一下吧)
代码如下:
#include <iostream>
using namespace std;
const int N = 500010;
int a[N];
int main()
{
int n;
scanf("%d",&n);
int ma = -1,mi = 10010;
for(int i = 0;i < n;i++)
{
scanf("%d",&a[i]);
ma = max(ma,a[i]);
mi = min(mi,a[i]);
}
int ans = 0;
int t;
bool flag;
for(int p = mi;p < ma;p++)
{
flag = true;
t = 0;
for(int i = 0;i < n;i++)
{
if(a[i] < p)
{
flag = true;//如果a[i]比划定的p小,那么a[i]此时就相当于0
}
else if(a[i] >= p && flag)//但如果a[i]大于划定的p并且此时的a[i]是0的后一位,那么就相当于出现了新的非零段
{
t++;
flag = false;
}
}
ans = max(ans,t);//ans取不同p划分中的最大值
}
printf("%d",ans);
return 0;
}
浅记一下满分做法:
(以下运用比喻句)这道题的意思相当于:
海平面原来是淹没所有山峰的,随着海平面的下降,逐渐有山峰露出来,问最多的时候是露出来几个山峰(此处插入我的绘图)
根据这张图可以惊奇的发现,随着海平面的下降,不断露出的山峰有四种情况:
① 突然出现的高峰,使答案++ ;② 原来的高峰被中间的低估连接,答案--
③④ 都是在原来基础上做的改变,并不影响答案
由此,对山峰的统计就成了比大小的问题,代码如下:
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 500010,M = 10010;
int cnt[M];
int a[N];
int main()
{
int n;
scanf("%d",&n);
for(int i = 1;i <= n;i++)
scanf("%d",&a[i]);
n = unique(a+1,a+n+1) - a - 1;//这里unique是把相邻的重复元素删到只剩一个,方便运算且对答案没影响
a[0] = a[n+1] = 0;
for(int i = 1;i <= n;i++)
{
int x1 = a[i-1],x2 = a[i],x3 = a[i+1];
if(x1 < x2 && x3 < x2)
cnt[x2]++;//山峰
if(x1 > x2 && x3 > x2)
cnt[x2]--;//山谷
}
int sum = 0,ans = 0;
for(int i = M;i >= 1;i--)
{
sum += cnt[i];
ans = max(ans,sum);
}
printf("%d",ans);
return 0;
}
补充unique:unique函数返的返回值是一个迭代器,它指向的是去重后容器中不重复序列的最后一个元素的下一个元素。剩余元素个数 n = unique(数组起始,数组末尾)- 数组起始。
(第三题写了再补,暂时就这么多)