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],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] = 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          for(int k=l;k<r;k++)
22              f[l][r] = max(calc(f[l][k],f[k+1][r],op[k+1]),f[l][r]);
23      }
24 }
25 int main() 
26 {
27     scanf("%d",&n);
28     for(int i=1;i<=n;i++)
29     {
30         scanf("%s%d",s,&nums[i]);
31         if(s[0]=='t') op[i] = 1;
32         else op[i] = 0;
33         nums[i+n] = nums[i];
34         op[i+n] = op[i];
35     }
36     memset(f,-0x3f,sizeof f);
37     ans = -0x3f3f3f3f;
38     solve();
39     for(int i=1;i<=n;i++) ans = max(ans,f[i][i+n-1]);
40     printf("%d\n",ans);
41     for(int i=1;i<=n;i++)
42       if(f[i][i+n-1]==ans)
43            printf("%d ",i);
44     return 0;
45 }

 

上一篇:个人早期写的一些组件


下一篇:CSS实现等分布局的4种方式