题目链接: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 }