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;
}
路漫漫其修远兮,吾将上下而求索