Codeforces Round #616(Div2)B.Array Sharpening

B.Array Sharpening(传送门)
题意
给你一个数组,判断 在对数组中的元素进行不限次数的-1操作后数组是否能变成锐化数组
锐化数组
1.数组为单调递增
2.数组为单调递减
3.数组先单调递增后单调递减
由题意易知
数组中的元素是否满足题意 与该元素的值和该元素所处的位置有关

举个例子
数组 a[1,2,3,4,2,6,7,8,6,4,5,4,1,2]
将数组平均分为两部分
左侧为 a1[1,2,3,4,2,6,7] 右侧为a2[8,6,4,5,1,2]
满足题意的左侧数组在经过-1操作后必须是单调递增的,则将最左侧元素减到0能更容易使它小于右侧的数,从而保持子区间上的单调递增。
往右操作 操作使第二个元素等于1 能更容易使它小于右侧的数,从而保持子区间上的单调递增。


由规律可知 第i个元素的值xi应该满足xi>=i-1
右侧数组满足从左往右是递减的 即从右往左是递增的
所以我们可以同时对左右侧数组进行判断

对于有偶数个元素的数组我们要判断在组数中点两侧的元素值是否相等
有两种情况(xi的情况在之前已经排除)
1. 两个元素相等但大于所处位置的索引值
这种情况可以将其中一个减1 从而符合题意
2.两个元素相等且等于所处位置的索引值
无法进行-1操作 因为-1的话会不符合xi>=i-1这个条件
此情况不符合题意
下面附上完整代码(仅供参考)

#include
using namespace std;
const int N = 3e5 + 10;
int a[N];
int main()
{
	int t;cin >> t;
	while (t--)
	{
		int n;cin >> n;
		for (int i = 1;i <= n;i++)
			cin >> a[i];
		int mid = n / 2;
		int flag = 1;
		if (n & 1)
		{
			for (int i = 1;i <= mid+1;i++)
			{
				if (a[i] < i - 1 || a[n - i + 1] < i - 1)flag = 0;
			}
		}
		else
		{
			for (int i = 1;i <= mid&&flag;i++)
			{
				if (a[i] < i - 1 || a[n - i + 1] < i - 1)flag = 0;
			}
			if (a[mid] == mid - 1 && a[mid + 1] == mid - 1)flag = 0;
		}
		if (flag)cout << "YES" << endl;
		else cout << "NO" << endl;
		memset(a, 0, sizeof(int));
	}
	return 0;
}

你可能感兴趣的:(codeforces)