题解 CF1421E 【Swedish Heroes】

· · 题解

Description

长度为 n 的数列 \big<a_i\big>,一次操作可以把两个相邻的数 a_ia_{i+1} 合并成 -(a_i+a_{i+1}),请最大化 n-1 次操作后剩下的数。

1\le n\le 200000,-10^9\le a_i \le10^9

Solution

所有操作相当于给每个数前面分配一个 +-,然后加起来。

很容易想到一个 \Theta(n^3) 的区间DP,设 f_{l,r} 表示合并 [l,r] 中的数后能得到的最大值,g_{l,r} 表示合并 [l,r] 中的数后能得到的最小值,有转移

f_{l,r}=\max_{l\le i < r}\{-(g_{l,i}+g_{i+1,r})\} g_{l,r}=\min_{l\le i < r}\{-(f_{l,i}+f_{i+1,r})\}

然而这一点儿用都没有,没有任何优化余地。

凭经验可知我们一定少了什么observation ,是否所有合法的分配方案都满足一个简单的性质呢?

观察一下

$n=2$ `--`; $n=3$ `++-`,`-++`; $n=4$ `----`,`+---`,`-+--`,`--+-`,`---+`; …… (我也不知道要多敏锐的洞察力才能)发现: 设 `-` 的个数为 $p$ ,`+` 的个数为 $q$,则 $$2p+q\equiv1\pmod{3}$$ 证明用归纳法,假设 $n$ 成立,新合并一个数后,$p'=q+1$,$q'=p$,那么 $$2A=2*(2p'+q')\equiv4q+4+2p\pmod{3}$$ 因为 $2p+q\equiv1\pmod{3} 2A\equiv3q+5\pmod{3} 2A\equiv2\pmod{3} A\equiv1\pmod{3}

n+1 也成立。

但是别高兴得太早,这只是合法方案的必要条件,不是充分条件。事实上有这样一个corner case:类似+-+-... 或者 -+-+... 这样加减交错的情况一定是不合法的,因为第一次操作的两个数最后符号一定相同。

整理一下,合法的分配方案满足:

  1. 至少存在一对相邻且符号相同的数。

根据这两点设计一个DP:
f_{i,j,0/1,0/1} 表示考虑了前 i 个数,2p+q\equiv j\pmod{3},第 i 个数的符号为 -+,否/是存在至少一对相邻且符号相同的数,的答案。
转移枚举 a_i 的符号:

f_{i+1,(j+2)\bmod3,0,t|(k==0)}\gets f_{i,j,k,t}-a_{i+1} f_{i+1,(j+1)\bmod3,1,t|(k==1)}\gets f_{i,j,k,t}+a_{i+1}

边界 f_{1,2,0,0}=-a_1,f_{1,1,1,0}=a_1

## Comment 为我们提供了一种找规律的方向:**观察模性质**。 ## Code ```cpp #include<bits/stdc++.h> #define mk make_pair #define pk push_back using namespace std; typedef long long LL; typedef pair<int,int> pi; template<class T> bool cmax(T &x,T y){return y>x?x=y,1:0;} template<class T> bool cmin(T &x,T y){return y<x?x=y,1:0;} const int N=2e5+5; int n,a[N]; LL f[N][3][2][2]; int main(){ ios::sync_with_stdio(false); cin>>n; for(int i=1;i<=n;++i) cin>>a[i]; if(n==1){ cout<<a[1]<<endl; return 0; } memset(f,-0x3f,sizeof f); f[1][2][0][0]=-a[1]; f[1][1][1][0]=a[1]; for(int i=1;i<n;++i) for(int j=0;j<3;++j) for(int k=0;k<2;++k) for(int t=0;t<2;++t) cmax(f[i+1][(j+2)%3][0][t|(k==0)],f[i][j][k][t]-a[i+1]), cmax(f[i+1][(j+1)%3][1][t|(k==1)],f[i][j][k][t]+a[i+1]); cout<<max(f[n][1][0][1],f[n][1][1][1])<<endl; return 0; } ```