P4342 [IOI1998]Polygon

P4342 [IOI1998]Polygon

题目链接

​ 明显区间DP。

​ 首先断环成链,然后枚举要删除哪条边。\(f[l][r], g[l][r]\)分别表示区间\([l, r]\),可以算出的最大值和最小值。瞎搞转移一下就好了。

​ 为啥必须弄最小值?因为某些最大值是由最小值转移过来的,可能有两个区间的最小值为负数,一乘就变成了一个大的正数。(一开始没写最小值调了好久)

#include <bits/stdc++.h>
    
using namespace std;
    
inline long long read() {
    long long s = 0, f = 1; char ch;
    while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
    for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
    return s * f;
}
    
const int N = 205;
long long n, num, ans;
long long a[N], val[N], edge[N], f[N][N], g[N][N];
char ch[N], cha[N][N];

void copy(int x) {
    for(int i = x; i <= x + n - 1; i++) {
        val[i - x + 1] = a[i];
        cha[i - x][i - x + 1] = ch[i];  
    }
}

long long calc(long long x, long long y, char z) {
    if(z == 't') return x + y;
    if(z == 'x') return x * y;
}

void work(int x) {
    copy(x);
    for(int i = 1;i <= n; i++) 
        for(int j = 1;j <= n; j++) g[i][j] = 1e17, f[i][j] = -1e17;
    for(int i = 1;i <= n; i++) g[i][i] = f[i][i] = val[i];
    
    for(int len = 2; len <= n; len++) {
        for(int l = 1; l <= n; l++) {
            int r = l + len - 1; if(r > n) break;
            for(int i = l + 1; i <= r; i++) {
                f[l][r] = max(f[l][r], calc(f[l][i - 1], f[i][r], cha[i - 1][i]));
                f[l][r] = max(f[l][r], calc(f[l][i - 1], g[i][r], cha[i - 1][i]));
                f[l][r] = max(f[l][r], calc(g[l][i - 1], f[i][r], cha[i - 1][i]));
                f[l][r] = max(f[l][r], calc(g[l][i - 1], g[i][r], cha[i - 1][i]));
                g[l][r] = min(g[l][r], calc(g[l][i - 1], g[i][r], cha[i - 1][i]));
                g[l][r] = min(g[l][r], calc(g[l][i - 1], f[i][r], cha[i - 1][i]));
                g[l][r] = min(g[l][r], calc(f[l][i - 1], g[i][r], cha[i - 1][i]));
                g[l][r] = min(g[l][r], calc(f[l][i - 1], f[i][r], cha[i - 1][i]));
            }
        }
    }
    if(ans < f[1][n]) {
        ans = f[1][n];
        edge[num = 0] = x;
    }
    if(ans == f[1][n]) edge[++num] = x;
}

int main() {

    n = read();

    for(int i = 1; i <= n; i++) {
        cin >> ch[i]; ch[n + i] = ch[i];
        a[i] = read(); a[n + i] = a[i];
    }

    ans = -1e17;
    for(int i = 1;i <= n; i++) work(i);

    printf("%lld\n", ans);
    for(int i = 1; i <= num; i++) printf("%d ", edge[i]);

    return 0;
}
posted @ 2020-09-09 06:18  C锥  阅读(94)  评论(0编辑  收藏  举报