洛谷 P4342 [IOI1998]Polygon(区间DP)

题目链接:https://www.luogu.com.cn/problem/P4342

考虑断掉哪条边,可以将区间变成环,然后进行区间DP。

因为数据有负数,而两个负数(最小值)相乘可能是最大值,或者正数乘负数可能是最小值等情况。所以要保存最大值和最小值。

所以设f[i][j][0/1]表示[i,j]区间所能求得的最大/小值。DP后用ans记录长度为n的最大值。然后再扫一遍,如果有长度为n的最大值等于ans,则将i都输出。

AC代码:

 1 #include<cstdio>
 2 #include<iostream>
 3 using namespace std;
 4 int n;
 5 const int N=105;
 6 char op[N];
 7 int a[N];
 8 int f[N][N][2],ans;
 9 int main(){
10     scanf("%d",&n);
11     for(int i=1;i<=n;i++){
12         cin>>op[i]>>a[i];
13         a[i+n]=a[i]; op[i+n]=op[i];
14     }
15     for(int i=1;i<=2*n;i++)
16     for(int j=1;j<=2*n;j++) f[i][j][0]=-0x3f3f3f3f,f[i][j][1]=0x3f3f3f3f;
17     for(int i=1;i<=2*n;i++) f[i][i][0]=f[i][i][1]=a[i];
18     for(int l=1;l<=n;l++)
19     for(int i=1;i<=2*n;i++){
20         int j=i+l;
21         if(j>2*n) break;
22         for(int k=i+1;k<=j;k++){
23             if(op[k]=='x'){
24                 f[i][j][0]=max(f[i][j][0],max(f[i][k-1][0]*f[k][j][0],f[i][k-1][1]*f[k][j][1]));
25                 f[i][j][1]=min(f[i][j][1],min(f[i][k-1][0]*f[k][j][1],min(f[i][k-1][1]*f[k][j][0],f[i][k-1][1]*f[k][j][1])));
26             }
27             else{
28                 f[i][j][0]=max(f[i][j][0],f[i][k-1][0]+f[k][j][0]);
29                 f[i][j][1]=min(f[i][j][1],f[i][k-1][1]+f[k][j][1]);
30             }
31         }
32     }
33     for(int i=1;i<=n;i++) ans=max(ans,f[i][i+n-1][0]); printf("%d
",ans);
34     for(int i=1;i<=n;i++) if(f[i][i+n-1][0]==ans) printf("%d ",i);
35     return 0;
36 }
AC代码
原文地址:https://www.cnblogs.com/New-ljx/p/13701781.html