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 ;
}
posted @ 2020-10-19 18:48  Soulist  阅读(108)  评论(0编辑  收藏  举报