【Codeforces】1832C - Contrast Value

题目:

For an array of integers [a1,a2,…,an], let's call the value |a1−a2|+|a2−a3|+⋯+|an−1−an| the contrast of the array. Note that the contrast of an array of size 11 is equal to 00.

You are given an array of integers a. Your task is to build an array of b in such a way that all the following conditions are met:

  • b is not empty, i.e there is at least one element;
  • b is a subsequence of a, i.e b can be produced by deleting some elements from a (maybe zero);
  • the contrast of b is equal to the contrast of a.

What is the minimum possible size of the array b?

输入:

The first line contains a single integer  t  (1 ≤ t ≤ 10^4) — the number of test cases.

The first line of each test case contains a single integer  n  (1 ≤ n ≤ 3·10^5) — the size of the array  a .

The second line contains  n  integers a1,a2,...,an ( 0 ≤ ai ≤ 10^9 ) — elements of the array itself.

The sum of  n  over all test cases doesn't exceed  3·10^5 .

输出:

For each test case, print a single integer — the minimum possible size of the array  b .


分析:

        通过题意可知,对于 1 3 3 3 7 这样的数据,其中至少有两个3是不影响结果的,也就是说,我们可以将这组数据变成这样:1 3 7 a1 = 1 , a2 = 3 , a3 = 7 , | a1 - a2 | = 2 , | a2 - a3 | =  4 ,  所以最后结果就是 2 + 4 = 6,官方题解就是这样做的,那么还有没有其他办法?

        当然有了,没有我写这个干嘛。

        进一步观察 | a1 - a3 | = 6,也是答案,也就是说我们可以直接省略 3 了 ,那么换个思路:

        运用数形结合的方法,计算绝对值还相当于计算两数在数轴上的距离,那么这就是一条从1到7 的线段,其中有三个节点,除了两端点就是处于线段中的点 3 了,从1加到3再加到7和直接从1加到7有区别吗?当然没有所以对于一组单调的数据,我们只需要保留端点就行了,那如果不单调呢?

        对于 5 4 2 1 0 0 4 ,这样的数据,首先在5 - 0(1)上递减,接着0 - 4(2)递增,在线段(1)上有两个端点5 0,在线段(2)上有两个端点0 4,但是0已经统计过了,所以答案就是3。

以此类推所有 “0” 这样的转折点都只记录一次,在整个数据中的两个端点记录一次,所以最终答案就是  转折点的数量+端点数(2),依据于此,开始写代码


#include<bits/stdc++.h>
using namespace std;
int tagg(int a,int b)//tag=0代表num与prenum相等,tag=1代表递减,tag=-1代表递增
{
    return (a>b?1:(a==b?0:-1));
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t;
    cin >> t;
    while(t--)
    {
        int ans{};
        int n,num,prenum,tag{};//prenum记录上一个数,tag记录当前状态
        cin >> n >> prenum;//因为至少有一个数,所以先输入n和prenum
        if(n==1) //如果n=1那么就不用继续下去了,直接输出就行
        {
            cout << "1\n";
            continue;
        }
        cin >> num;
        tag = tagg(prenum,num);
        for(int i = 2;i < n;i++)
        {
            prenum = num;
            cin >> num;
            if(tag&&-tag == tagg(prenum,num)) { ans++;tag = -tag; }//当单调趋势改变时,代表转折点出现
            if(!tag) tag = tagg(prenum,num);//这里防止tag从一开始就等于0导致上边不能正常判断
        }
        if(!tag&&!ans) cout << "1\n";//所有数字一样输出1
        else if(!ans) cout << "2\n";//存在不一样的数但是整体单调性没变输出端点数也就是2
        else cout << ans + 2 << endl;//转折点+两个端点就是答案
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值