P4342 [IOI1998]Polygon

原题链接

考察:区间DP

思路:

        f[i][j]表示[i,j]区间的最大得分,那么状态转移方程f[l][r] = max(f[l][r],calc(f[l][k],f[k+1][r],op[k+1])

        calc函数是什么呢,根据定义f[i][j]表示i,j区间合并后的最大得分,calc就是再将f[l][k]与f[k+1][r]合并,op[k+1]就是边的符号.信心满满的交上去后,可以过四个点

        那么哪里出了问题呢?注意到数字有负数,并且存在乘法,因此最大值可能是两个负数最小值相乘,也可能是正数最大值相加(乘).因此这道题要计算最大值,还需要记录区间计算的最小值.注意最小值是由两区间最大值或最小值转移而来.

        最后枚举断点,当前断点就是第一步要断的边.

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 using namespace std;
 5 const int N = 110,M =2;
 6 int nums[N],n,f[N][N][2],ans;
 7 bool op[N];//1表示+ 0表示* 
 8 char s[M];
 9 int calc(int a,int b,int x)
10 {
11     if(x) return a+b;
12     else return a*b;
13 }
14 void solve()
15 {
16     for(int i=1;i<=2*n;i++) f[i][i][1] = f[i][i][0] = nums[i];
17     for(int len=2;len<=n*2;len++)
18      for(int l=1;l+len-1<=2*n;l++)
19      {
20          int r = l+len-1;
21          f[l][r][1] = -0x3f3f3f3f;
22          f[l][r][0] = 0x3f3f3f3f;
23          for(int k=l;k<r;k++)
24          {
25              f[l][r][1] = max(calc(f[l][k][1],f[k+1][r][1],op[k+1]),f[l][r][1]);
26              f[l][r][1] = max(calc(f[l][k][0],f[k+1][r][0],op[k+1]),f[l][r][1]);
27              f[l][r][0] = min(calc(f[l][k][0],f[k+1][r][0],op[k+1]),f[l][r][0]);
28              f[l][r][0] = min(calc(f[l][k][1],f[k+1][r][1],op[k+1]),f[l][r][0]);
29          }
30      }
31 }
32 int main() 
33 {
34     scanf("%d",&n);
35     for(int i=1;i<=n;i++)
36     {
37         scanf("%s%d",s,&nums[i]);
38         if(s[0]=='t') op[i] = 1;
39         else op[i] = 0;
40         nums[i+n] = nums[i];
41         op[i+n] = op[i];
42     }
43     ans = -0x3f3f3f3f;
44     solve();
45     for(int i=1;i<=n;i++) ans = max(ans,f[i][i+n-1][1]);
46     printf("%d\n",ans);
47     for(int i=1;i<=n;i++)
48       if(f[i][i+n-1][1]==ans)
49            printf("%d ",i);
50     return 0;
51 }

 

posted @ 2021-04-06 01:48  acmloser  阅读(46)  评论(0编辑  收藏  举报