单调队列题目练习
Posted saigyouji-yuyuko
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单调队列题目练习相关的知识,希望对你有一定的参考价值。
RT。由于本人dp很弱(或者说什么都弱),于是决定分模块刷题。单调队列就找了些题目(我水平已经沦落到了普及组qwq)练,顺便把以前做过的题都堆起来。以后做到的题再开新文章。
1.多重背包
不说了,很好推。放许久之前的幼稚代码
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int MAXN=1000+7; 4 const int MAXV=10000+7; 5 inline int Read(){ 6 int x=0,f=0;char ch; 7 while(!isdigit(ch=getchar()))if(ch==‘-‘) f=1; 8 while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^‘0‘),ch=getchar(); 9 return f?-x:x; 10 } 11 int dp[2][MAXV]; 12 int q[MAXV]; 13 int key[MAXV]; 14 int T,n,W,f,r,val,w,k,ans,p; 15 16 int main(){ 17 T=Read(); 18 while(T--){ 19 W=Read(),n=Read();memset(dp,0,sizeof dp);p=0; 20 for(register int i=1;i<=n;++i,p^=1){ 21 w=Read(),val=Read(),k=Read(); 22 for(register int j=0;j<w;++j){ 23 q[f=r=1]=0;key[1]=dp[p][j]=dp[p^1][j];//重点在这个dp[i][j]=dp[i-1][j]我漏掉了,这个也是必须要延续的! 24 for(register int l=1;l*w+j<=W;++l){ 25 int x=dp[p^1][l*w+j]-l*val; 26 while(f<=r&&key[r]<=x) --r; 27 q[++r]=l;key[r]=x; 28 while(f<=r&&q[f]<l-k) ++f; 29 dp[p][l*w+j]=key[f]+l*val; 30 } 31 } 32 } 33 printf("%d ",dp[n&1?0:1][W]); 34 } 35 return 0; 36 }
2.P3957 [NOIP2017T4]跳房子
套了一个二分答案的裸题,细节注意即可。
1 #include<bits/stdc++.h> 2 #define mid ((L+R)>>1) 3 using namespace std; 4 typedef long long ll; 5 const int N=500000+7; 6 const ll INF=5e10; 7 inline int read(){ 8 int x=0,f=0;char ch; 9 while(!isdigit(ch=getchar()))if(ch==‘-‘) f=1; 10 while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^‘0‘),ch=getchar(); 11 return f?-x:x; 12 } 13 ll dp[N]; 14 int x[N],s[N],q[N]; 15 int n,d,k,L=1,R=1e9,f,r; 16 17 inline int check(int g){ 18 int a=(d-g>0)?(d-g):1,b=d+g,y=1;register int i=1; 19 q[f=r=1]=0; 20 for(;x[i]<a;++i)dp[i]=-INF; 21 for(;i<=n;++i){ 22 while(x[y]<=x[i]-a){//重点,调了好久. 23 while(f<=r&&dp[y]>dp[q[r]])--r; 24 q[++r]=y++; 25 }//while(x[y]>=x[i]-b&&x[y]<=x[i]-a)这是本人原语句↑发现大数据过不了,主要是x[y]>=x[i]-b加上限制了前面dp的入队,导致y值一直就没办法增加了。 26 while(f<=r&&x[q[f]]<x[i]-b)++f; 27 if(dp[q[f]]==-INF||f>r){f=r;dp[i]=-INF;continue;} else dp[i]=(dp[q[f]]+(ll)s[i]); 28 if(dp[i]>=k) return 1; 29 } 30 return 0; 31 } 32 33 int main(){//freopen("tmp.in","r",stdin); 34 n=read(),d=read(),k=read(); 35 for(register int i=1;i<=n;++i) x[i]=read(),s[i]=read(); 36 while(L<R){ 37 if(check(mid)) R=mid; 38 else L=mid+1; 39 } 40 printf("%d ",R==1e9?-1:R); 41 return 0; 42 }
3.poj2373 dividing the path
因为是很久以前写的代码,有不足之处但是现在也不想改了。注意区间标记的使用!
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 using namespace std; 6 const int L=1000000+7; 7 const int INF=1000010; 8 inline int read(){ 9 int x=0,f=0;char ch; 10 while(!isdigit(ch=getchar()))if(ch==‘-‘) f=1; 11 while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^‘0‘),ch=getchar(); 12 return f?-x:x; 13 } 14 int dp[L],sum[L],q[L]; 15 int n,l,x,y,a,b,f=1,r=1; 16 //细节稍微有点多,qwq 17 int main(){ 18 n=read(),l=read(),a=read(),b=read(); 19 for(register int i=1;i<=n;++i) x=read(),y=read(),++sum[x+1],--sum[y]; 20 for(register int i=1;i<=l;++i) sum[i]+=sum[i-1],dp[i]=INF; 21 for(register int i=(a<<1);i<(b<<1);i+=2){ 22 if(!sum[i]) dp[i]=1; 23 while(f<=r&&dp[i-(a<<1)]<dp[q[r]])--r; 24 q[++r]=i-(a<<1); 25 } 26 for(register int i=(b<<1);i<=l;i+=2){ 27 while(f<=r&&dp[i-(a<<1)]<dp[q[r]])--r; 28 q[++r]=i-(a<<1); 29 if(sum[i]>0)continue; 30 while(q[f]<i-(b<<1)) ++f; 31 dp[i]=min(dp[i],dp[q[f]]+1); 32 } 33 printf("%d ",dp[l]>=INF?-1:dp[l]);//for(int i=0;i<=l;++i) cerr<<i<<" "<<dp[i]<<" "<<sum[i]<<endl; 34 return 0; 35 }
4.UVA1169 Robotruck
很正常的一道水题。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N=100000+7; 5 inline int read(){ 6 int x=0,f=0;char ch; 7 while(!isdigit(ch=getchar()))if(ch==‘-‘) f=1; 8 while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^‘0‘),ch=getchar(); 9 return f?-x:x; 10 } 11 ll dp[N],dis[N],w[N],to[N],x,y,z,Lastx,Lasty; 12 int q[N]; 13 int T,n,C,f,r; 14 15 inline ll F(int x){return dp[x]+to[x+1]-dis[x+1];} 16 17 int main(){ 18 T=read(); 19 while(T--){ 20 C=read(),n=read();q[f=r=1]=0,Lastx=Lasty=0; 21 for(register int i=1;i<=n;++i){ 22 x=read(),y=read(),z=read(); 23 to[i]=x+y;dis[i]=dis[i-1]+abs(Lastx-x)+abs(Lasty-y);w[i]=w[i-1]+z; 24 Lastx=x;Lasty=y; 25 } 26 for(register int i=1;i<=n;++i){ 27 while(f<=r&&w[i]-w[q[f]]>C)++f; 28 dp[i]=F(q[f])+dis[i]+to[i]; 29 while(f<=r&&F(i)<F(q[r]))--r; 30 q[++r]=i; 31 } 32 printf("%lld ",dp[n]); 33 if(T) puts(""); 34 } 35 return 0; 36 }
5.P2627 修剪草坪
大水题,枚举断点即可。边界问题的话右移一个格子就行了。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 template<typename T>inline char MIN(T&A,T B){return A>B?A=B,1:0;} 5 template<typename T>inline char MAX(T&A,T B){return A<B?A=B,1:0;} 6 template<typename T>inline T _min(T A,T B){return A<B?A:B;} 7 template<typename T>inline T _max(T A,T B){return A>B?A:B;} 8 template<typename T>inline T read(T&x){ 9 x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c==‘-‘)f=1; 10 while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x; 11 } 12 const int N=100000+7; 13 ll f[N],a[N],sum[N]; 14 int q[N]; 15 int n,k,l,r; 16 inline ll F(int i){return f[i-1]-sum[i];} 17 //连单调队列也不会了。。 18 int main(){//freopen("tmp.in","r",stdin);freopen("tmp.out","w",stdout); 19 read(n),read(k); 20 for(register int i=2;i<=n+1;++i)sum[i]=read(a[i])+sum[i-1]; 21 q[l=r=1]=1; 22 for(register int i=2;i<=n+1;++i){ 23 while(l<=r&&q[l]<i-k)++l; 24 f[i]=_max(f[i-1],F(q[l])+sum[i]);//cerr<<q[l]<<" "<<f[i]<<endl; 25 while(l<=r&&F(q[r])<=F(i))--r; 26 q[++r]=i; 27 } 28 printf("%lld ",_max(f[n],f[n+1])); 29 return 0; 30 }
6.P1901 发射站
一开始是为了练单调队列,结果往单调队列上想了半天没想出来,只会用单调栈,A了之后看了一眼题解,单调队列做法不就是把单调栈另一头加了一个head吗。。被算法标签误导。而且这题其实也不是dp。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 template<typename T>inline char MIN(T&A,T B){return A>B?A=B,1:0;} 5 template<typename T>inline char MAX(T&A,T B){return A<B?A=B,1:0;} 6 template<typename T>inline T _min(T A,T B){return A<B?A:B;} 7 template<typename T>inline T _max(T A,T B){return A>B?A:B;} 8 template<typename T>inline T read(T&x){ 9 x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c==‘-‘)f=1; 10 while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x; 11 } 12 const int N=1000000+7; 13 int stk[N],r,n; 14 ll h[N],v[N],f[N],ans; 15 inline void dp(){ 16 for(register int i=2;i<=n;++i){ 17 while(r&&h[stk[r]]<=h[i])--r; 18 f[stk[r]]+=v[i];stk[++r]=i; 19 } 20 } 21 //连单调队列也不会了。。 22 int main(){//freopen("tmp.in","r",stdin);freopen("tmp.out","w",stdout); 23 read(n); 24 for(register int i=1;i<=n;++i)read(h[i]),read(v[i]); 25 stk[r=1]=1,dp(); 26 reverse(h+1,h+n+1),reverse(v+1,v+n+1),reverse(f+1,f+n+1); 27 stk[r=1]=1,dp(); 28 for(register int i=1;i<=n;++i)MAX(ans,f[i]); 29 printf("%lld ",ans); 30 return 0; 31 }
以上是关于单调队列题目练习的主要内容,如果未能解决你的问题,请参考以下文章