这个题的难度是绿色,众所周知青菜是绿色的,所以这题一定很菜,实际上确实是(你不还是看了题解)
我们可以设计出这样一个状态:f[l][r]代表从l到r的最高加分,结果就是f[1][n]
怎样转移?
一棵子树肯定要有根,所以我们就枚举根!
在一段区间[i,j]里,揪出来一个根k,然后转移:f[l][r]=max(f[l][k-1]*f[k+1][r]+f[k][k])
其中f[k][k]显然就是自身的权值了
因为揪出根之后剩下的区间一定比之前小,所以要按长度从小往大枚举区间
输出的话记录一下i到j这棵子树揪出来的根就好啦~
Code:
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cmath> 4 #include<ctime> 5 #include<cstring> 6 #include<iostream> 7 #include<algorithm> 8 #include<stack> 9 #include<queue> 10 #include<vector> 11 #include<bitset> 12 #include<set> 13 #include<map> 14 #define LL long long 15 #define rg register 16 #define us unsigned 17 #define eps 1e-6 18 #define INF 0x3f3f3f3f 19 #define ls k<<1 20 #define rs k<<1|1 21 #define tmid ((tr[k].l+tr[k].r)>>1) 22 #define nmid ((l+r)>>1) 23 #define Thispoint tr[k].l==tr[k].r 24 #define pushup tr[k].wei=tr[ls].wei+tr[rs].wei 25 #define pub push_back 26 #define lth length 27 #define int long long 28 using namespace std; 29 inline void Read(int &x){ 30 int f=1; 31 char c=getchar(); 32 x=0; 33 while(c<'0'||c>'9'){ 34 if(c=='-')f=-1; 35 c=getchar(); 36 } 37 while(c>='0'&&c<='9'){ 38 x=(x<<3)+(x<<1)+c-'0'; 39 c=getchar(); 40 } 41 x*=f; 42 } 43 #define N 40 44 int n,f[N][N],pr[N][N]; 45 inline void Initi(){ 46 Read(n); 47 for(rg int i=1;i<=n;i++){ 48 Read(f[i][i]); 49 pr[i][i]=i; 50 } 51 } 52 inline void Solve(){ 53 for(rg int len=1;len<n;len++){ 54 for(rg int l=1;l+len<=n;l++){ 55 int r=l+len; 56 //初始情况 57 //加分:没有左子树一定最小 58 //根:先记上左端点 59 f[l][r]=f[l+1][r]+f[l][l],pr[l][r]=l; 60 for(rg int k=l+1;k<r;k++){ 61 if(f[l][r]<f[l][k-1]*f[k+1][r]+f[k][k]){ 62 f[l][r]=f[l][k-1]*f[k+1][r]+f[k][k]; 63 pr[l][r]=k;//转移+记录 64 } 65 } 66 } 67 } 68 } 69 inline void Print(int l,int r){ 70 if(l>r)return; 71 printf("%lld ",pr[l][r]); 72 if(l!=r){ 73 Print(l,pr[l][r]-1); 74 Print(pr[l][r]+1,r); 75 }else return; 76 } 77 signed main(){ 78 Initi(); 79 Solve(); 80 printf("%lld ",f[1][n]); 81 Print(1,n); 82 return 0; 83 }