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 }
心之所动 且就随缘去吧