CCF-CSP202109

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(数组起始,数组末尾)- 数组起始。

(第三题写了再补,暂时就这么多)

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值