Pokémon Army (hard version) -每天一把CF - 20201008

每天一把CF : 2020-10-08

文章目录

    • 题目
    • 思路
    • 代码实现

题目

原题链接:https://codeforc.es/problemset/problem/1420/C2

Pokémon Army (hard version) -每天一把CF - 20201008_第1张图片

思路

题目大意:给你n个数,可以从中选任意个数(至少要选一个)组成一个新的数组,这个新的数组的价值计算方式为所有奇数索引项之和减去所有偶数索引项之和,即a1-a2+a3-a4+…现有一操作,将原来n个数中的li和ri位置的两个数互换。问没有操作和每次操作之后(操作是叠加的)能得到的字数列最大价值是多少。

思路:(需要结合easy版本的一起看)

在easy版本中我们已经知道最后我们要求的值实际上就是将这n个数化成折线图后曲率小于0(即成下降趋势的线段长度),而这个成下降趋势的长度的线段又由一个个小线段组成,就像下图就是a-b+c-d,具体证明可回到easy版本去看。

Pokémon Army (hard version) -每天一把CF - 20201008_第2张图片

现在我们有一个操作,将位于li和ri位置的两个数进行交换,要求我们求出交换后的新的最大价值。

结合上面的思路,实际上这两个点的交换后,我们要求的值还是下降趋势线段的长度,但是我们不可能再进行遍历,明明白白的会TLE。

再思考一下,交换了这两个点,实际上只是影响了a[li - 1] - a[li];a[li] - a[li + 1];a[ri - 1] - a[ri];a[ri] - a[ri + 1]四条小线段而已(这四条小线段会变成四条新的小线段),所以我们在原先的值得基础上除去原先原先这四条小线段的影响,然后加上四条新的小线段的长度(如果是下降趋势的话)。

然后注意边界条件:

  • li==1时li只能影响a[li] - a[li + 1]一条边
  • li+1==ri时两个点总共只能影响三条线段.
  • li==ri时 值不会发生任何变化

最后的最后,该开longlong就开longlong,不要犹豫,犹豫就会败北。

代码实现

#include 
#include 
#include 
using namespace std;

#define ll long long
const int MAX = 3E5 + 5;


ll t, n, q;
ll a[MAX];

void swap(ll* a, ll* b) {
     
	//更换元素,防止之后的操作与现在的元素有关
	ll tp = *a;
	*a = *b;
	*b = tp;
}

ll pro(ll ans, ll li, ll ri) {
     

	if (li == ri)
		return ans;
	else if (li + 1 == ri)
	{
     
		ans -= max(0ll, a[li - 1] - a[li]);
		ans -= max(0ll, a[li] - a[li + 1]);
		ans -= max(0ll, a[ri] - a[ri + 1]);
		swap(&a[li], &a[ri]);
		ans += max(0ll, a[li - 1] - a[li]);
		ans += max(0ll, a[li] - a[li + 1]);
		ans += max(0ll, a[ri] - a[ri + 1]);
	}
	else if (li == 1 || ri == n)
		if (li != 1)//ri==n
		{
     
			ans -= max(0ll, a[li - 1] - a[li]);
			ans -= max(0ll, a[li] - a[li + 1]);
			ans -= max(0ll, a[ri - 1] - a[ri]);
			ans -= max(0ll, a[ri] - a[ri + 1]);
			swap(&a[li], &a[ri]);
			ans += max(0ll, a[li - 1] - a[li]);
			ans += max(0ll, a[li] - a[li + 1]);
			ans += max(0ll, a[ri - 1] - a[ri]);
			ans += max(0ll, a[ri] - a[ri + 1]);
		}
		else if (ri != n)//li==1
		{
     
			ans -= max(0ll, a[li] - a[li + 1]);
			ans -= max(0ll, a[ri - 1] - a[ri]);
			ans -= max(0ll, a[ri] - a[ri + 1]);
			swap(&a[li], &a[ri]);
			ans += max(0ll, a[li] - a[li + 1]);
			ans += max(0ll, a[ri - 1] - a[ri]);
			ans += max(0ll, a[ri] - a[ri + 1]);
		}
		else
		{
     
			ans -= max(0ll, a[li] - a[li + 1]);
			ans -= max(0ll, a[ri - 1] - a[ri]);
			ans -= max(0ll, a[ri] - a[ri + 1]);
			swap(&a[li], &a[ri]);
			ans += max(0ll, a[li] - a[li + 1]);
			ans += max(0ll, a[ri - 1] - a[ri]);
			ans += max(0ll, a[ri] - a[ri + 1]);

		}
	else
	{
     
		ans -= max(0ll, a[li - 1] - a[li]);
		ans -= max(0ll, a[li] - a[li + 1]);
		ans -= max(0ll, a[ri - 1] - a[ri]);
		ans -= max(0ll, a[ri] - a[ri + 1]);
		swap(&a[li], &a[ri]);
		ans += max(0ll, a[li - 1] - a[li]);
		ans += max(0ll, a[li] - a[li + 1]);
		ans += max(0ll, a[ri - 1] - a[ri]);
		ans += max(0ll, a[ri] - a[ri + 1]);
	}
	return ans;
}


int main() {
     
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	cin >> t;
	while (t--)
	{
     
		memset(a, 0, sizeof(a));
		cin >> n >> q;
		for (int i = 1; i <= n; i++)
			cin >> a[i];
		ll ans = 0;
		for (int i = 1; i <= n; i++)
			ans += max(0ll, a[i] - a[i + 1]);
		cout << ans << endl;
		//cout << "---->" << ans << endl;

		while (q--) {
     
			ll li, ri;
			cin >> li >> ri;
			ans = pro(ans, li, ri);
			cout << ans << endl;
			//cout << "---->" << ans << endl;
		}
	}


	return 0;
}

你可能感兴趣的:(OJ,#,每天一把CF,算法)