[2020.11.13]AGC035D - Add and Remove
阿新 • • 發佈:2020-11-13
題意
給出一個長度為\(n\)的序列\(A\),每次可以做如下操作:
任取一個整數\(w\),滿足\(2\le w\le\)當前序列長度 ,令\(A_{w-1}\)和\(A_{w+1}\)加上\(A_w\),然後刪去\(a_w\)。
重複上述操作直到序列長度為\(2\),求最終\(A_1+A_2\)的最小值。
題解
不妨倒著考慮整個過程。每次考慮當前最後一個被刪除的數並加入。
設\(V_x\)表示\(A_x\)向最終總和的貢獻次數,一開始\(V_1=V_n=1\),那麼設當\(x\)被加入時,它左邊第一個已經被加入的數是\(L\),右邊是\(R\),那麼\(V_x=V_L+V_R\)。
於是,我們記\(dp_{l,r,x,y}\)
那麼
\[dp_{l,r,x,y}=\min_{m=l+1}^{r-1}dp_{l,m,x,x+y}+dp_{m,r,x+y,y}+A_m\times(x+y) \]注意到狀態中的\(x,y\)都是\(O(2^n)\)級別,因此可以使用\(map\)和記憶化搜尋實現。
code:
#include<bits/stdc++.h> #define ci const int& using namespace std; struct sta{ int l,r,x,y; bool operator<(const sta&t)const{ return l==t.l?(r==t.r?(x==t.x?y<t.y:x<t.x):r<t.r):l<t.l; } }; int n,a[20]; map<sta,long long>dp; long long DP(ci l,ci r,ci x,ci y){ if(l>=r-1)return 0; if(dp.count((sta){l,r,x,y}))return dp[(sta){l,r,x,y}]; long long tmp=1e18; for(int i=l+1;i<r;++i)tmp=min(tmp,DP(l,i,x,x+y)+DP(i,r,x+y,y)+1ll*a[i]*(x+y)); return dp[(sta){l,r,x,y}]=tmp; } int main(){ scanf("%d",&n); for(int i=1;i<=n;++i)scanf("%d",&a[i]); printf("%lld",DP(1,n,1,1)+a[1]+a[n]); return 0; }