复习动规
Posted manmanjiangqwq
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了复习动规相关的知识,希望对你有一定的参考价值。
今天早上换寝室,耽误了一些时间。还是继续复习动态规划。
单调队列优化dp
第一道,宝物筛选。一道多重背包优化题。如果用二进制优化很好做,但时间复杂度是O(nW*logm)。单调队列优化做法如下:
首先做出普通的多重背包的转移方程:f[j]=max{f[j-w*k]+v*k},w为重量,v为价值。
使得j=aw+b,即a=j/w,b=j%w。原方程可转化为f[j]=max{f[(a-k)*w+b]-(a-k)*v}+a*v。
这个时候我们就可以枚举b,将a-k看做整体,对于每个b都对f[(a-k)*w+b]-(a-k)*v做单调队列,再将a从大到小循环就可以了。
方程的转化比较难想到,代码的具体实现如下:
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=4e4+1e3; 4 int n,W,p[N]; 5 long long f[N],q[N]; 6 long long Max(long long x,long long y){ 7 return x>y?x:y; 8 } 9 int Min(int x,int y){ 10 return x<y?x:y; 11 } 12 int rd(){ 13 int s=0,ff=1; 14 char w=getchar(); 15 while(!isdigit(w)) 16 ff^=w==‘-‘,w=getchar(); 17 while(isdigit(w)) 18 s=s*10+w-‘0‘,w=getchar(); 19 return ff?s:-s; 20 } 21 int main(){ 22 int v,w,m,l,r,a; long long x; 23 n=rd(); W=rd(); 24 for(int i=1;i<=n;i++){ 25 v=rd(),w=rd(),m=rd(); 26 for(int b=0;b<w;b++){ 27 l=1,r=0,a=(W-(W%w-b+w)%w)/w; 28 for(int k=1;k<=Min(a,m);k++){ 29 x=f[(a-k)*w+b]-(a-k)*v; 30 while(l<=r&&q[r]<=x) r--; 31 q[++r]=x,p[r]=a-k; 32 } 33 for(int j=W-(W%w-b+w)%w;j!=b;j-=w){ 34 a=j/w; while(p[l]>=a) l++; 35 f[j]=Max(f[j],q[l]+a*v); 36 if(a>=m+1) x=f[(a-m-1)*w+b]-(a-m-1)*v; 37 while(l<=r&&q[r]<=x) r--; 38 q[++r]=x,p[r]=a-m-1; 39 } 40 } 41 } 42 printf("%lld ",f[W]); 43 return 0; 44 }
数据结构优化dp
第一道,"动态 DP"&动态树分治。剩下的大多数时间都花在上面了,头疼。
动态DP具体的思想和做法看这篇博客吧,个人觉得写的非常好。
我在这里讲下操作的具体实现(为了方便表达,把新定义的符号叫做乘号):
对于点x,它的权值要改为y,首先它树上的矩阵要先修改(别忘了权值要改)。
然后进入while循环,先求出Top[x](Top[x]为x所在重链的顶点)的f值,求法是对x这一整条重链即线段树上的连续一段求矩阵的连乘,因为叶子节点的f值等于g值,所以乘出来后矩阵第1行第1列就是f[i][0],第2行第1列就是f[i][1]。
再用树上x的矩阵更新线段树上x的矩阵,之后再求出Top[x]的f值。
再就可以用Top[x]的新旧f值修改树上“Top[x]的父亲”的矩阵(具体实现看代码,好理解的)。然后x=“Top[x]的父亲”。
然后while循环结束了,不用担心Top[x]的父亲也就是现在的x没有在线段树上更新,因为在下个循环会更新到的。
答案就是求出1的f值,取最大值输出即可。代码具体实现如下:
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=1e5+1e4; 4 int n,m,cnt,tot,h[N],d[N],f[N][2],g[N][2],fa[N],dep[N],siz[N],Son[N],Top[N],dfn[N],sfn[N],End[N]; 5 int Max(int x,int y){ 6 return x>y?x:y; 7 } 8 struct nod{ 9 int nxt,to; 10 }a[N*2]; 11 struct Num{ 12 int p[3][3]; 13 Num(){ 14 memset(p,0,sizeof(p)); 15 p[2][2]=-1e8; 16 } 17 inline Num operator*(Num b){ 18 Num c; 19 for(int i=1;i<=2;i++) 20 for(int j=1;j<=2;j++) 21 for(int k=1;k<=2;k++) 22 c.p[i][j]=Max(c.p[i][j],p[i][k]+b.p[k][j]); 23 return c; 24 } 25 }b[N*4],c[N],ans; 26 int rd(){ 27 int s=0,ff=1; 28 char w=getchar(); 29 while(!isdigit(w)) 30 ff^=w==‘-‘,w=getchar(); 31 while(isdigit(w)) 32 s=s*10+w-‘0‘,w=getchar(); 33 return ff?s:-s; 34 } 35 void Add(int x,int y){ 36 a[++cnt].nxt=h[x]; 37 a[cnt].to=y; 38 h[x]=cnt; 39 } 40 void Dfs(int x,int w){ int y; siz[x]=1; 41 for(int i=h[x];i;i=a[i].nxt){ 42 y=a[i].to; 43 if(y==w) continue ; fa[y]=x; 44 dep[y]=dep[x]+1; Dfs(y,x); 45 siz[x]+=siz[y]; 46 if(siz[y]>siz[Son[x]]) 47 Son[x]=y; 48 } 49 } 50 void Dfss(int x,int w){ int y; 51 dfn[++tot]=x; sfn[x]=tot; 52 if(Son[x]) 53 Top[Son[x]]=Top[x],Dfss(Son[x],x),End[x]=End[Son[x]]; 54 else End[x]=x; 55 for(int i=h[x];i;i=a[i].nxt){ 56 y=a[i].to; 57 if(y==w||y==Son[x]) continue ; 58 Top[y]=y; Dfss(y,x); 59 } 60 61 } 62 void Dfs_dp(int x,int w){ int y; 63 f[x][0]=g[x][0]=0; f[x][1]=g[x][1]=d[x]; 64 for(int i=h[x];i;i=a[i].nxt){ 65 y=a[i].to; if(y==w) continue ; Dfs_dp(y,x); 66 f[x][0]+=Max(f[y][0],f[y][1]),f[x][1]+=f[y][0]; 67 if(y!=Son[x]) 68 g[x][0]+=Max(f[y][0],f[y][1]),g[x][1]+=f[y][0]; 69 } 70 } 71 void Build(int x,int l,int r){ 72 if(l==r){ 73 b[x].p[1][1]=g[dfn[l]][0]; 74 b[x].p[1][2]=g[dfn[l]][0]; 75 b[x].p[2][1]=g[dfn[l]][1]; 76 b[x].p[2][2]=-1e8; 77 c[dfn[l]]=b[x]; return ; 78 } 79 int mid=(l+r)>>1; 80 Build(x<<1,l,mid); 81 Build(x<<1|1,mid+1,r); 82 b[x]=b[x<<1]*b[x<<1|1]; 83 } 84 void Update(int x,int l,int r,int s){ 85 if(l==r){ 86 b[x]=c[dfn[l]]; return ; 87 } 88 int mid=(l+r)>>1; 89 if(s<=mid) Update(x<<1,l,mid,s); 90 else Update(x<<1|1,mid+1,r,s); 91 b[x]=b[x<<1]*b[x<<1|1]; 92 } 93 Num Query(int x,int l,int r,int L,int R){ 94 if(L<=l&&r<=R) return b[x]; 95 int mid=(l+r)>>1; 96 if(mid>=R) return Query(x<<1,l,mid,L,R); 97 else if(mid<L) return Query(x<<1|1,mid+1,r,L,R); 98 else return Query(x<<1,l,mid,L,R)*Query(x<<1|1,mid+1,r,L,R); 99 } 100 int main(){ 101 int x,y,z; Num A,B; 102 n=rd(); m=rd(); 103 for(int i=1;i<=n;i++) 104 d[i]=rd(); 105 for(int i=1;i<n;i++) 106 x=rd(),y=rd(),Add(x,y),Add(y,x); 107 dep[1]=1; Dfs(1,0); 108 Top[1]=1; Dfss(1,0); 109 Dfs_dp(1,0); Build(1,1,n); 110 while(m--){ 111 x=rd(),y=rd(); 112 c[x].p[2][1]+=y-d[x]; d[x]=y; 113 while(x){ 114 A=Query(1,1,n,sfn[Top[x]],sfn[End[x]]); 115 Update(1,1,n,sfn[x]); 116 B=Query(1,1,n,sfn[Top[x]],sfn[End[x]]); 117 x=fa[Top[x]]; 118 c[x].p[1][1]+=Max(B.p[1][1],B.p[2][1])-Max(A.p[1][1],A.p[2][1]); 119 c[x].p[1][2]+=Max(B.p[1][1],B.p[2][1])-Max(A.p[1][1],A.p[2][1]); 120 c[x].p[2][1]+=B.p[1][1]-A.p[1][1]; 121 } 122 A=Query(1,1,n,sfn[1],sfn[End[1]]); 123 printf("%d ",Max(A.p[1][1],A.p[2][1])); 124 } 125 return 0; 126 }
今天就这样吧,看了几题比较简单就没写了,明天再说。
以上是关于复习动规的主要内容,如果未能解决你的问题,请参考以下文章