【题目链接】
http://www.lydsy.com/JudgeOnline/problem.php?id=1564
【题意】
给定一个Treap,总代价为深度*距离之和。可以每次以K的代价修改权值,问最小代价。
【思路】
数据值是不变的,因此Treap的中序遍历是唯一的。先将数据按照数据值排序,得到其中序遍历。
然后将权值离散化到[1,n]区间内。
设f[l][r][w]为区间[l,r]内的权值都比w大时的最小代价,则有转移式:
f[l][r][w]=min { f[l][k-1][w]+f[k+1][r][w]+K+c(l,r) }
f[l][r][w]=min { f[l][k-1][a[k].w]+f[k+1][r][a[k].w]+c(l,r) },a[k].w>=w
记忆化搜索比较好写lalala
【代码】
1 #include<set> 2 #include<cmath> 3 #include<queue> 4 #include<vector> 5 #include<cstdio> 6 #include<cstring> 7 #include<iostream> 8 #include<algorithm> 9 #define trav(u,i) for(int i=front[u];i;i=e[i].nxt) 10 #define FOR(a,b,c) for(int a=(b);a<=(c);a++) 11 using namespace std; 12 13 typedef long long ll; 14 const int N = 105; 15 const int inf = 1e9; 16 17 struct Node 18 { 19 int dat,w,c; 20 bool operator < (const Node& rhs) const 21 { 22 return dat<rhs.dat; 23 } 24 } a[N]; 25 26 int n,K,sumc[N],f[N][N][N]; 27 pair<int,int> b[N]; 28 29 int dp(int l,int r,int w) 30 { 31 int& ans=f[l][r][w]; 32 if(l>r) return ans=0; 33 if(ans!=-1) return ans; 34 ans=inf; 35 FOR(k,l,r) { 36 if(a[k].w>=w) 37 ans=min(ans,dp(l,k-1,a[k].w)+dp(k+1,r,a[k].w)+sumc[r]-sumc[l-1]); 38 ans=min(ans,dp(l,k-1,w)+dp(k+1,r,w)+sumc[r]-sumc[l-1]+K); 39 } 40 return ans; 41 } 42 43 int main() 44 { 45 // freopen("in.in","r",stdin); 46 // freopen("out.out","w",stdout); 47 memset(f,-1,sizeof(f)); 48 scanf("%d%d",&n,&K); 49 FOR(i,1,n) scanf("%d",&a[i].dat); 50 FOR(i,1,n) scanf("%d",&a[i].w); 51 FOR(i,1,n) scanf("%d",&a[i].c); 52 sort(a+1,a+n+1); 53 FOR(i,1,n) 54 b[i]=make_pair(a[i].w,i); 55 sort(b+1,b+n+1); 56 FOR(i,1,n) 57 a[b[i].second].w=i, 58 sumc[i]=sumc[i-1]+a[i].c; 59 60 int ans=inf; 61 FOR(i,1,n) 62 ans=min(ans,dp(1,n,i)); 63 printf("%d",ans); 64 return 0; 65 }