Loading

CF1421E Swedish Heroes

CF1421E Swedish Heroes

比赛的时侯倒开翻车,下分下惨了/ll,就是因为这道题

大大大大大大大大大大结论题

发现每个数对于答案的贡献要么是 \(a_i\) ,要么是 \(-a_i\)

那么系数的序列 \(+-+-++--\cdots\) 必须满足以下两个条件

  • 必须存在两个相同的系数相邻

  • 设有 \(p\)\(-\)\(q\)\(+\) ,那么 \(2p+q\equiv 1\pmod 3\)

直接设 \(dp[i][j][0/1][0/1]\) 表示:第 \(i\) 位,模 \(3\) 的余数,这一位的系数,是否存在两个相同的系数相邻

\(dp\) 一遍 \(O(n)\) ,完结撒花!

这结论为啥是对的啊???

用归纳法

首先对于 \(n\in [1,3]\) 结论正确

对于 \(n\ge 4\)

合并以后 \(p'=q+1,q'=p\)

\(2(2p'+q')\equiv 4q+4+2p\equiv 3q+5\equiv 2 \pmod 3\)

所以 \(2p'+q'\equiv 1\pmod 3\)

但是完全交错是不合法的,第一次操作的那两个数符号一定相同,直接被捆到了一起。

#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef long long LL;
typedef double db;
#define rep(i,x,y) for(int i=x,i##end=y;i<=i##end;++i)
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=0;ch=getchar();}
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return f?x:-x;
}
const int N = 200005;
int n, a[N], dp[N][3][2][2];//pos=i,2'-'+'+',+1-0,continueop
void ckmax(int&x, int y){if (x < y) x = y; }
signed main() {
	n = read();
	for (int i = 1; i <= n; ++ i) a[i] = read();
	if (n == 1) return printf("%lld\n", a[1]), 0;
	memset(dp, -0x3f, sizeof(dp));
	dp[1][2][0][0] = - a[1], dp[1][1][1][0] = a[1];
	for (int i = 1; i < n; ++ i) {
		for (int j = 0; j < 3; ++ j) {
			ckmax(dp[i + 1][(j + 1) % 3][1][1], max(dp[i][j][1][0], max(dp[i][j][1][1], dp[i][j][0][1])) + a[i + 1]);
			ckmax(dp[i + 1][(j + 1) % 3][1][0], dp[i][j][0][0] + a[i + 1]);
			ckmax(dp[i + 1][(j + 2) % 3][0][1], max(dp[i][j][0][0], max(dp[i][j][0][1], dp[i][j][1][1])) - a[i + 1]);
			ckmax(dp[i + 1][(j + 2) % 3][0][0], dp[i][j][1][0] - a[i + 1]);
		}
	}
	printf("%lld\n",max(dp[n][1][0][1], dp[n][1][1][1]));
	return 0;
}
posted @ 2020-10-24 11:10  zzctommy  阅读(175)  评论(0编辑  收藏  举报