(mathcal{Description})
Link.
给定一个长为 (n) 的非负整数序列 (lang a_n ang),你可以进行如下操作:
- 取 ([l,r]),将其中所有 (a) 值 (-1);
- 取 ([l,r]),将其中奇数下标的 (a) 值 (-1);
- 取 ([l,r]),将其中偶数下标的 (a) 值 (-1)。
求至少需要几次操作使得所有 (a) 值变为 (0)。
(nle10^5),数据组数 (Tle10)。
(mathcal{Solution})
道路铺设永放光芒!
记集族 (mathcal I) 包括所有一次操作可能涉及的下标集合,写出线规
[operatorname{minimize}~~~~z=sum_{Pin mathcal I}x_P\
operatorname{s.t.} egin{cases}
forall u,~sum_{P
i u}x_Pge a_u\
forall u,~-sum_{P
i u}x_Pge -a_u\
forall P,~x_Pge 0
end{cases}
]
转对偶
[operatorname{maximize}~~~~z'=sum_{u=1}^na_u(s_u-t_u)\
operatorname{s.t.}egin{cases}
forall P,~sum_{uin P}(s_u-t_i)le1\
forall u,~s_u,t_uge0
end{cases}
]
令 (d_u=s_u−t_u),由第一个约束,显然有 (d_ule1);而为最大化 (sum_{u=1}^na_ud_u),可以得到 (d_uin{-1,0,1})。那么就能简单 DP:令 (f(i,x,y,z)) 表示考虑了 (d_{1..i}),一类/二类/三类操作涉及的操作集合中,最大后缀 (d) 之和为 (x/y/z~(in{0,1})),枚举 (d_u=1,2,3) 分别转移即可。
复杂度 (mathcal O(Tn))(其实带一个 (ge log n) 的 (24) 倍常数 qwq)。
(mathcal{Code})
/*~Rainybunny~*/
#include <cstdio>
#include <cstring>
#define rep( i, l, r ) for ( int i = l, rep##i = r; i <= rep##i; ++i )
#define per( i, r, l ) for ( int i = r, per##i = l; i >= per##i; --i )
typedef long long LL;
inline int rint() {
int x = 0, f = 1, s = getchar();
for ( ; s < '0' || '9' < s; s = getchar() ) f = s == '-' ? -f : f;
for ( ; '0' <= s && s <= '9'; s = getchar() ) x = x * 10 + ( s ^ '0' );
return x * f;
}
template<typename Tp>
inline void wint( Tp x ) {
if ( x < 0 ) putchar( '-' ), x = -x;
if ( 9 < x ) wint( x / 10 );
putchar( x % 10 ^ '0' );
}
template<typename Tp>
inline void chkmax( Tp& a, const Tp& b ) { a < b && ( a = b, 0 ); }
inline int imax( const int a, const int b ) { return a < b ? b : a; }
const int MAXN = 1e5;
const LL LINF = 1ll << 60;
int n, a[MAXN + 5];
LL f[MAXN + 5][2][2][2];
int main() {
for ( int T = rint(); T--; ) {
n = rint();
rep ( i, 1, n ) a[i] = rint();
memset( f, 0xc0, sizeof f );
f[0][0][0][0] = 0;
rep ( i, 1, n ) rep ( w, -1, 1 ) {
rep ( x, 0, 1 ) rep ( y, 0, 1 ) rep ( z, 0, 1 ) {
if ( w + x <= 1 && w + ( i & 1 ? y : z ) <= 1 ) {
chkmax( f[i][imax( imax( w, w + x ), 0 )]
[i & 1 ? imax( imax( w, w + y ), 0 ) : y]
[i & 1 ? z : imax( imax( w, w + z ), 0 )],
f[i - 1][x][y][z] + w * a[i] );
}
}
}
LL ans = -LINF;
rep ( x, 0, 1 ) rep ( y, 0, 1 ) rep ( z, 0, 1 ) {
chkmax( ans, f[n][x][y][z] );
}
wint( ans ), putchar( '
' );
}
return 0;
}