CF1421E
CF1421E
可以证明一个 \(+1/-1\) 序列合法当且仅当:
- 其长度加上其中 \(-1\) 的数量在模 \(3\) 意义下为 \(1\)
- 其中存在两个连续的 \(1\) 或者 \(-1\)
可以这样考虑,我们的操作本质上合并得到了一棵树,那么自顶而下的考虑这个模型,每次操作可以视为选择 \(x\) 然后给 \([1,x],[x+1,n]\) 的子树分别乘以 \(-1\) 并合并起来,假设子模型满足此限制,那么就有 \(n_1+f_1\mod 3=1,n_2+f_2\mod 3=1\),显然合并之后原本的 \(1\) 的数量为 \(f=f_1+f_2\),此时有 \(n+f\mod 3=2\),于是翻转后变成 \(2n-f=2(n+f)-3f\mod 3=1\)
于是我们证明了必要性,再证明充分性,可以考虑这样来构造方案,选定一对 \(-1\) 合并起来并变成 \(1\)(\(1\) 同理),如果两边有 \(1/-1\) 就继续合并,否则此时是 01 交错的形式,那么可以调整这次合并直到合并成仅剩一个。
然后实际上还有一个条件是合并之后要恰好为 \(+1\),然后 \(\mod 3=1\) 的条件保证了这个性质。
于是可以直接 dp 处理了。
\(Code\):
#include<bits/stdc++.h>
using namespace std ;
#define Next( i, x ) for( register int i = head[x]; i; i = e[i].next )
#define rep( i, s, t ) for( register int i = (s); i <= (t); ++ i )
#define drep( i, s, t ) for( register int i = (t); i >= (s); -- i )
#define re register
#define int long long
int gi() {
char cc = getchar() ; int cn = 0, flus = 1 ;
while( cc < '0' || cc > '9' ) { if( cc == '-' ) flus = - flus ; cc = getchar() ; }
while( cc >= '0' && cc <= '9' ) cn = cn * 10 + cc - '0', cc = getchar() ;
return cn * flus ;
}
const int N = 2e5 + 5 ;
int n, a[N], dp[N][4][2][2] ;
void cx(int &x, int y) { x = max(x, y) ; }
signed main()
{
n = gi() ;
rep( i, 1, n ) a[i] = gi() ;
if( n == 1 ) { cout << a[1] << endl ; exit(0) ; }
memset( dp, -63, sizeof(dp) ) ;
dp[1][1][1][0] = a[1] ;
dp[1][2][0][0] = -a[1] ;
rep( i, 2, n ) {
rep( j, 0, 2 ) rep( k, 0, 1 ) rep( l, 0, 1 ) {
cx( dp[i][(j + 1) % 3][1][l | (k == 1)], dp[i - 1][j][k][l] + a[i] ) ;
cx( dp[i][(j + 2) % 3][0][l | (k == 0)], dp[i - 1][j][k][l] - a[i] ) ;
}
}
cout << max( dp[n][1][0][1], dp[n][1][1][1] ) << endl ;
return 0 ;
}