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;
}