洛谷P1880 [NOI1995]石子合并 (区间dp

题目描述

在一个圆形操场的四周摆放 N 堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。

试设计出一个算法,计算出将 N 堆石子合并成 11 堆的最小得分和最大得分。

 

其实是简单区间dp板子题,但是因为是圆形操场加上数据范围合理所以就把环形数据改成两倍(手动加区间(就是其实也就是把可以选择的区间按照圆形可选种类扩了一下,其余不怎么变的

 

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define fi first
 4 #define se second
 5 #define pi acos(-1.0)
 6 #define mp make_pair
 7 #define pb push_back
 8 #define ls rt<<1
 9 #define rs rt<<1|1
10 #define inf 0x3f3f3f3f
11 #define pll pair<LL, LL>
12 #define pii pair<int, int>
13 #define mem(a, b) memset(a, b, sizeof(a))
14 #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
15 
16 typedef long long ll;
17 const int N  = 2e5+5;
18 const int M  = 200+5;
19 const int mod = 1e9+7;
20 //head
21 int a[M],sum[M],dps[M][M],dpl[M][M];
22 int n,anss,ansl,tpn;
23 int main(){
24     fio
25     cin>>n;    tpn = n*2;    sum[0] = 0;
26     
27     for(int i = 1;i <= n;++i){cin>>a[i];sum[i] = a[i]+sum[i-1];    }
28     for(int i = n+1;i <=tpn;++i){a[i] = a[i-n];sum[i] = a[i]+sum[i-1];}
29     
30     for(int len = 2;len<=n;++len){//当前维护区间长度
31         for(int i = 1,j;i+len-1<=tpn;++i){//起始位置
32             j =  i+len-1;dps[i][j] = inf;//因为要取最小值所以初始化为最大值
33             for(int k = i;k < j;++k){//枚举间断处
34                 dps[i][j] = min(dps[i][k] + dps[k+1][j] + sum[j]-sum[i-1],dps[i][j]);
35                 dpl[i][j] = max(dpl[i][k] + dpl[k+1][j] + sum[j]-sum[i-1],dpl[i][j]);
36             }
37         }
38     }
39     anss = dps[1][n];ansl = dpl[1][n];
40     for(int i = 1;i <= n;++i){
41         anss = min(dps[i][i+n-1],anss);    
42         ansl = max(dpl[i][i+n-1],ansl);
43     }
44     cout<<anss<<endl;cout<<ansl<<endl;
45     return 0;
46 }

 

posted @ 2020-01-15 15:07  小草今天又在摸鱼吗  阅读(142)  评论(0编辑  收藏  举报