luogu P1880 [NOI1995]石子合并 区间DP

这么水的题不想水博客来着,但是感觉这种把原序列倍增后,进行区间DP的思路很奇妙,记录一下。

因为是一个环,所以对原序列倍增后,再进行DP,最后枚举起始位置。

dp[i][j]表示[i,j]这一段合并产生的最大/最小价值。

 1 #include <cstdio>
 2 #include <algorithm>
 3 using namespace std;
 4 typedef long long ll;
 5 int n;
 6 ll vec[220],res[2];
 7 ll dp[220][220][2];
 8 ll dfs(int l,int r,int opt)
 9 {
10     if (dp[l][r][opt] != 0 || l == r)
11         return dp[l][r][opt];
12     if (opt == 0)
13         dp[l][r][opt] = 100000000000000;
14     for (int i = l;i <= r - 1;i++)
15         if (opt == 1)
16             dp[l][r][opt] = max(dfs(l,i,opt) + dfs(i + 1,r,opt),dp[l][r][opt]);
17         else
18             dp[l][r][opt] = min(dfs(l,i,opt) + dfs(i + 1,r,opt),dp[l][r][opt]);
19     dp[l][r][opt] += vec[r] - vec[l - 1];
20     return dp[l][r][opt];
21 }
22 int main()
23 {
24     scanf("%d",&n);
25     for (int i = 1;i <= n;i++)
26         scanf("%lld",&vec[i]);
27     for (int i = n + 1;i <= 2 * n;i++)
28         vec[i] = vec[i - n];
29     for (int i = 1;i <= 2 * n;i++)
30         vec[i] += vec[i - 1];
31     res[0] = 100000000000000;
32     for (int i = 1;i <= n + 1;i++)
33     {
34         res[0] = min(res[0],dfs(i,i + n - 1,0));
35         res[1] = max(res[1],dfs(i,i + n - 1,1));
36     }
37     printf("%lld\n%lld\n",res[0],res[1]);
38     return 0;
39 }

 

posted @ 2019-03-20 16:52  IAT14  阅读(166)  评论(0编辑  收藏  举报