CF1421E
可以证明一个 (+1/-1) 序列合法当且仅当:
- 其长度加上其中 (-1) 的数量在模 (3) 意义下为 (1)
- 其中存在两个连续的 (1) 或者 (-1)
可以这样考虑,我们的操作本质上合并得到了一棵树,那么自顶而下的考虑这个模型,每次操作可以视为选择 (x) 然后给 ([1,x],[x+1,n]) 的子树分别乘以 (-1) 并合并起来,假设子模型满足此限制,那么就有 (n_1+f_1mod 3=1,n_2+f_2mod 3=1),显然合并之后原本的 (1) 的数量为 (f=f_1+f_2),此时有 (n+fmod 3=2),于是翻转后变成 (2n-f=2(n+f)-3fmod 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 ;
}