Link: 4441: Necklace
Solution:只有十个可以当中间数的,那么我们枚举中间数,然后从左从右分别进行DP,再枚举断点,维护答案最大值即可。
转移方程也很好想:
dp1[i] = max(dp[i-1], max{ dp1[j] | j < i, a[i] <= a[j] } + a[i]) (右半部分)
dp2[i] = max(dp[i+1], max{ dp2[j] | j > i, a[i] <= a[j] } + a[i])(左半部分)
显然这个DP要用线段树或者树状数组来加速,树状数组要好写一些,复杂度
AC Code:
template<class T> inline T qmax(T a, T b) { return a > b ? a : b; }
int n;
int a[maxn<<1], b[maxn], c[maxn];
int dp1[maxn], dp2[maxn];
int getmax(int x){
int ret = 0;
for( ; x > 0; ret = qmax(ret, c[x]), x -= lowbit(x));
return ret;
}
void update(int x, int val){
for ( ; x <= maxn; c[x] = qmax(c[x], val), x += lowbit(x));
}
int ans = 0;
void solve(int pos){
int tot = 0;
rep(i, pos + 1, pos + n - 1){
if(a[i] != 10000) b[++tot] = a[i];
}
memset(c, 0, sizeof(c));
dp1[0] = 0;
rep(i, 1, tot){
int t = getmax(10000 - b[i]);
dp1[i] = max(dp1[i-1], t + b[i]);
update(10000 - b[i], t + b[i]);
}
memset(c, 0, sizeof(c));
dp2[tot+1] = 0;
Rep(i, tot, 1){
int t = getmax(10000 - b[i]);
dp2[i] = max(dp2[i+1], t + b[i]);
update(10000 - b[i], t + b[i]);
}
int Max = 0;
rep(i, 1, tot){
Max = qmax(Max, dp1[i] + dp2[i+1]);
}
ans = max(ans, Max + 10000);
}
int main()
{
while(~scanf("%d", &n)){
ans = 0;
rep(i, 1, n) scanf("%d", a + i), a[n+i] = a[i];
rep(i, 1, n){
if(a[i] == 10000) solve(i);
}
printf("%d\n", ans);
}
return 0;
}
当然线段树也是可以写的,只不过常数大了一些(而且赛场上并不好敲)
template<class T> inline T qmax(T a, T b) { return a > b ? a : b; }
int a[maxn<<1], b[maxn];
int dp1[maxn], dp2[maxn];
int n;
struct node{
int l, r, Max;
}tree[maxn<<2];
void push_up(int i){
tree[i].Max = qmax(tree[lson].Max, tree[rson].Max);
}
void build(int i, int l, int r){
tree[i].l = l, tree[i].r = r;
if(l == r) { tree[i].Max = 0; return ; }
int mid = (l + r) >> 1;
build(lson, l, mid);
build(rson, mid + 1, r);
push_up(i);
}
void update(int i, int pos, int val){
if(tree[i].l == pos && tree[i].r == pos) { tree[i].Max = val; return ; }
tree[i].Max = qmax(tree[i].Max, val);
int mid = (tree[i].l + tree[i].r) >> 1;
if(pos <= mid) update(lson, pos, val);
else update(rson, pos, val);
}
int Query(int i, int l, int r){
if(tree[i].l == l && tree[i].r == r) return tree[i].Max;
int mid = (tree[i].l + tree[i].r) >> 1;
if(r <= mid) return Query(lson, l, r);
else if(l > mid) return Query(rson, l, r);
else {
int ta = Query(lson, l, mid);
int tb = Query(rson, mid + 1, r);
return qmax(ta, tb);
}
}
int ans = 0;
void solve(int pos){
int tot = 0;
rep(i, pos + 1, pos + n - 1){
if(a[i] != 10000) b[++tot] = a[i];
}
build(1, 1, 10000);
dp1[0] = 0;
rep(i, 1, tot){
int t = Query(1, 1, 10000 - b[i]);
dp1[i] = max(dp1[i-1], t + b[i]);
update(1, 10000 - b[i], t + b[i]);
}
build(1, 1, 10000);
dp2[tot+1] = 0;
Rep(i, tot, 1){
int t = Query(1, 1, 10000 - b[i]);
dp2[i] = max(dp2[i+1], t + b[i]);
update(1, 10000 - b[i], t + b[i]);
}
int Max = 0;
rep(i, 1, tot){
Max = qmax(Max, dp1[i] + dp2[i+1]);
}
ans = max(ans, Max + 10000);
}
int main()
{
while(~scanf("%d", &n)){
ans = 0;
rep(i, 1, n) scanf("%d", a + i), a[n+i] = a[i];
rep(i, 1, n){
if(a[i] == 10000) solve(i);
}
printf("%d\n", ans);
}
return 0;
}
over