【題解】LOJ #2292. 「THUSC 2016」成績單【20201124 NOIP 模擬賽】【區間DP】
阿新 • • 發佈:2020-11-24
題意
今有一個序列 \(w\),給定 \(a,b\),你一次操作可以選擇區間 \([l,r]\),花費 \(a+b(\max_{i=l}^r w_i-\min_{i=l}^r w_i)^2\),並將這段區間刪掉。問將序列刪空的最小花費。\(n\leq 50\)
題解
設 \(f[l,r]\) 為刪除 \([l,r]\) 的最小花費,\(g[l,r,p,q]\) 為刪除 \([l,r]\) 的一部分部分直到剩下的最小值為 \(p\),最大值為 \(q\) 的最小花費。
- 用 \(g[l,r,p,q]+a+b(q-p)^2\) 更新 \(f[l,r]\);
- 用 \(g[l,r,p,q]\)
- 用 \(g[t,l-1,p,q]+f[l,r]\) 更新 \(g[t,r]\)(把 \([l,r]\) 拆出去)。
\(O(n^5)\) DP。
#include<bits/stdc++.h> using namespace std; const int N=52; int f[N][N],g[N][N][N][N],w[N],v[N],m,n,a,b; int main(){ scanf("%d%d%d",&n,&a,&b); for(int i=0;i<n;i++)scanf("%d",w+i),v[i]=w[i]; sort(v,v+n); m=unique(v,v+n)-v; for(int i=0;i<n;i++)w[i]=lower_bound(v,v+m,w[i])-v; memset(f,0x3f,sizeof(f)); memset(g,0x3f,sizeof(g)); for(int r=0;r<n;r++){ for(int l=r;~l;l--){ int mx=-23333,mn=23333; for(int i=l;i<=r;i++)mx=max(mx,w[i]),mn=min(mn,w[i]); g[l][r][mx][mn]=0; for(int p=0;p<m;p++) for(int q=p;q<m;q++){ f[l][r]=min(f[l][r],g[l][r][p][q]+a+b*(v[q]-v[p])*(v[q]-v[p])); if(r+1<n){ int &g_=g[l][r+1][min(p,w[r+1])][max(q,w[r+1])]; g_=min(g_,g[l][r][p][q]); } } for(int p=0;p<m;p++) for(int q=p;q<m;q++) for(int t=0;t<l;t++) g[t][r][p][q]=min(g[t][r][p][q],g[t][l-1][p][q]+f[l][r]); } } cout<<f[0][n-1]<<endl; }