[LUOGU] P4342 [IOI1998]Polygon

poj挂了快两天了。。

洛谷的今日运势真的强,说能完成WA的题就能完成。。

咳咳,区间DP。

思路类似合并果子,不过在维护f[i][j] (i到j的最大值) 同时也要维护g[i][j] (i到j的最小值

为什么呢?考虑把区间劈成左右两个的一次转移:
对于加法:
1.最大值显然是左右的最大值之和 max+max
对于乘法:
1.最大值是左右区间最大值的乘积 max*max
2.以及最小值的乘积(负数情况) min*min

因此要同时维护一下最小值才行,具体做法:
对于加法:
1.最小值是左右最小值之和
对于乘法:
1.左右最小值的乘积
2.左最小值*右最大值
3.左最大值*右最小值

对于环的处理:断开,复制一倍

手c数组真的很危险。。WA的原因是只初始化[0,n]的数组,[n+1,n*2]的没管。

emacs默认的两格缩进自己看还行,好像发上来效果很挤?

#include<iostream>
#include<cstdio>

using namespace std;

const int MAXN=500;
const int INF=1<<30;
int n;

char op[MAXN];
int f[MAXN][MAXN],g[MAXN][MAXN];
int main(){
  scanf("%d",&n);
  for(int i=0;i<=2*n;i++){//2*
    for(int j=0;j<=2*n;j++){//2*
      f[i][j]=-INF;
      g[i][j]=INF;
    }
  }
  for(int i=1;i<=n;i++){
    char s[5];
    scanf("%s%d",s,&f[i][i]);
//    cin>>op[i-1]>>f[i][i];
    g[i][i]=f[i][i];
    g[i+n][i+n]=f[i+n][i+n]=f[i][i];
    op[i+n-1]=op[i-1]=s[0];
  }
  op[n<<1]=op[0];
  for(int len=1;len<=n;len++){
    for(int i=1;i+len<=2*n;i++){//2*
      int j=i+len;
      for(int k=i;k<j;k++){
        if(op[k]=='t'){
          f[i][j]=max(f[i][j],f[i][k]+f[k+1][j]);
          g[i][j]=min(g[i][j],g[i][k]+g[k+1][j]);
        }else{
          f[i][j]=max(f[i][j],max(f[i][k]*f[k+1][j],g[i][k]*g[k+1][j]));
          g[i][j]=min(g[i][j],min(g[i][k]*g[k+1][j],min(g[i][k]*f[k+1][j],f[i][k]*g[k+1][j])));
        }
      }
    }
  }
  int mx=-INF;
  for(int i=1;i<=n;i++)mx=max(mx,f[i][i+n-1]);
  cout<<mx<<endl;
  for(int i=1;i<=n;i++){
    if(f[i][i+n-1]==mx)cout<<i<<" ";
  }
  return 0;
}

本文来自博客园,作者:GhostCai,转载请注明原文链接:https://www.cnblogs.com/ghostcai/p/9247424.html

原文地址:https://www.cnblogs.com/ghostcai/p/9247424.html