Codeforces Round #616 (Div. 2)B. Array Sharpening

关于这道题的题解报告

题目

题目连接
B. Array Sharpening

You’re given an array a1,…,an of n non-negative integers.

Let’s call it sharpened if and only if there exists an integer 1≤k≤n such that a1<a2<…<ak ,ak>ak+1>…>an. In particular, any strictly increasing or strictly decreasing array is sharpened. For example:

The arrays [4][0,1], [12,10,8] and [3,11,15,9,7,4] are sharpened;
The arrays [2,8,2,8,6,5], [0,1,1,0] and [2,5,6,9,8,8] are not sharpened.
You can do the following operation as many times as you want: choose any strictly positive element of the array, and decrease it by one. Formally, you can choose any i (1≤i≤n) such that ai>0 and assign ai:=ai−1.

Tell if it’s possible to make the given array sharpened using some number (possibly zero) of these operations.

Input
The input consists of multiple test cases. The first line contains a single integer t (1≤t≤15 000) — the number of test cases. The description of the test cases follows.

The first line of each test case contains a single integer n (1≤n≤3⋅105).

The second line of each test case contains a sequence of n non-negative integers a1,…,an (0≤ai≤109).

It is guaranteed that the sum of n over all test cases does not exceed 3⋅105.

Output
For each test case, output a single line containing “Yes” (without quotes) if it’s possible to make the given array sharpened using the described operations, or “No” (without quotes) otherwise.

Example
input

10
1
248618
3
12 10 8
6
100 11 15 9 7 8
4
0 1 1 0
2
0 0
2
0 1
2
1 0
2
1 1
3
0 1 0
3
1 0 1

output

Yes
Yes
Yes
No
No
Yes
Yes
Yes
Yes
No

Note
In the first and the second test case of the first test, the given array is already sharpened.

In the third test case of the first test, we can transform the array into [3,11,15,9,7,4] (decrease the first element 97 times and decrease the last element 4 times). It is sharpened because 3<11<15 and 15>9>7>4.

In the fourth test case of the first test, it’s impossible to make the given array sharpened.

题目大意

这道题的意思是给你一个非负整数的数组,要求你判断是否能够找出一个k使得a1<a2<…<ak ,ak>ak+1>…>an,也可整个数组严格单调递增或单调递减若要使得其左边严格单调递增右边严格单调递减,你可以对每个数做任意次减法(只要大于等于0),如果可以就输出"Yes",否则输出“No”

思路

  • 首先,我们要找出这个“最大值”
    先举一个栗子,比如:0 1 2 3 2 1 0,可以看出3就是最大值,并且3的左边严格单调递增,右边单调递减。那么可以得出结论,3左边的每一个数的最小值都等于其数组下标 i-1(数组下标从1开始),而3右边的每一个数的最小值都等于 n-i(n为数组长度,i为数组下标)
  • 如果任意一个数小于最小值都不能满足严格单调递增或严格单调递减。因为会产生负数

比如:0 1 1 3 2 1 0这种就输出"No"。
因此只要找出一个数a[i]小于i-1那么前面的数a[i-1]就是“最大值”

  • 其次找出“最大值”后还要有一个判定条件看其后面是否能够满足严格单调递减 (因为最大值前面每一个数都大于i-1可以减成等于i-1就能满足严格单调递增所以只需考虑最大值后面是否满足严格单调递减)

  • 如果要变成前面严格单调递增后面严格单调递减那么这个数组的长度必须小于等于2*最大值+1

比如0 1 2 3 2 1 0长度为7,满足题意,而0 1 2 3 2 1 0 0长度为8不满足题意,输出"No"因为3后面不是严格单调递减

解题步骤

  1. 遍历数组当a[i] < i-1时记录坐标i和a[i-1](最大值)如果找不到“最大值”则直接输出yes,因为每一项都满足a[i] > i-1那么就一定可以减成等于i-1满足严格单调递增
  2. 判断n (数组长度) 和 2 * a[i-1] + 1 的关系,如果大于则无法满足最大值后的数严格单调递减,输出"No",如果n = 1则直接输出"Yes"
  3. 如果 n <=2 * a[i-1] + 1则找出的这个最大值一定可以减完,那么就根据之前记录的下标遍历后面的数,如果找到任何一个数小于n - i(所能满足严格单调递减的最小值)就break输出"No"

代码块

#include <iostream>

using namespace std;
const int N = 3*1e5 + 5;
typedef long long ll;
ll a[N];
int main()
{
    ll t;
    cin >> t;
    while(t--)
    {
        ll n,p = -1/*保存最大值的值*/;
        cin >> n;
        int flag/*记录最大值后一项下标*/,mark = 0/*输出Yes or No的判断标志*/;
        for(int i = 1;i <= n; i++)
        {
            cin >> a[i];
        }
        if( n == 1)//n == 1则一定满足严格单调递增或减,直接输出yes
        {
            cout << "Yes" << endl;
            continue;
        }
        for(int i = 1;i <= n; i++)
        {
            if( a[i] < 0)//小于0直接输出No
            {
                mark = 1;
                break;
            }
            if( a[i] < i-1)//找到一个值小于i-1的,那么a[i-1]则为最大值
            {
                flag = i;//记录下标
                p = a[i-1];//记录最大值
                break;
            }
        }
        if(p >= 0 &&  n > 2 * p + 1)
        /*每一个数若要满足0,1,2,...p,p-1,p-2....1,0则长度最大为2*p+1,如0,1,2,3,2,1,0长度最大为2*3+1 = 7
        长度若大于此则一定减不完,若要满足后面严格单调递减就会出现负数*/
        {
            cout << "No" << endl;
            continue;
        }
        if( flag >= 0)//有最大值存在才进循环。否则直接输出Yes
        {
            for(int i = flag;i <= n; i++)
            {
                if( a[i] < n-i)//n-i是每一位数所能满足单调递减的最小值,若小于n-i就一定会出现负数
                {
                    mark = 1;
                    break;
                }
            }
        }

        if( mark )
        {
            cout << "No" << endl;
        }
        else
        {
            cout << "Yes" << endl;
        }
    }
    return 0;
}

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值