洛谷1063 +区间dp(经典问题)

题目网址:https://www.luogu.com.cn/problem/P1063

题意大致是:给定一个序列An,第i个元组表示为(Ai,Ai+1),序列位置不变,当合并一个区间[l,l+1]时开销是Al*Al+1*Al+2,问合并整个序列的最大开销。一看就是区间dp,顺便借助记忆化减少搜索的冗余。题目中的项链是环状的,可以通过拼接相同的序列在元序列之后构造出一条链状的序列。这个问题与矩阵链相乘有点相似。代码如下:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef unsigned int ui;
 4 typedef long long ll;
 5 typedef unsigned long long ull;
 6 #define pf printf
 7 #define mem(a) memset(a,0,sizeof(a))
 8 #define prime1 1e9+7
 9 #define prime2 1e9+9
10 #define scand(x) scanf("%llf",&x) 
11 #define f(i,a,b) for(int i=a;i<=b;i++)
12 #define scan(a) scanf("%d",&a)
13 #define dbg(args) cout<<#args<<":"<<args<<endl;
14 #define pb(i) push_back(i)
15 #define ppb(x) pop_back(x)
16 #define maxn 300
17 int n,m,t,a[maxn],ans=0;
18 int dp[maxn][maxn];
19 int dfs(int l,int r)//计算[l,r]区间合并的开销 
20 {
21     if(l==r)return 0;//单个的没有开销 
22     if(dp[l][r])return dp[l][r];
23     if(l==r-1) return a[l]*a[l+1]*a[r+1];//最小子问题,合并区间长度为2的两个 
24     int res=0;
25     f(i,l,r-1)
26     {
27         res=max(res,dfs(l,i)+dfs(i+1,r)+a[l]*a[i+1]*a[r+1]);//枚举两个子区间,有点分治的意味 
28     }
29     return dp[l][r]=res;
30 }
31 int main()
32 {
33     //freopen("input.txt","r",stdin);
34     //freopen("output.txt","w",stdout);
35     std::ios::sync_with_stdio(false);
36     scan(n);
37     mem(dp);
38     f(i,1,n)
39     {
40         scan(a[i]);
41         a[i+n]=a[i];//环状变为链状 
42     }
43     f(i,1,n)
44     {
45         ans=max(ans,dfs(i,n+i-1));
46     }
47     pf("%d",ans);
48  } 

 

posted @ 2020-03-01 11:55  WA自动机~  阅读(242)  评论(0编辑  收藏  举报