单调队列题目练习

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\n",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\n",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\n",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\n",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\n",_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\n",ans);
30     return 0;
31 }

原文地址:https://www.cnblogs.com/saigyouji-yuyuko/p/10420567.html

时间: 2024-10-10 18:29:12

单调队列题目练习的相关文章

hdu2430 Beans 单调队列

// hdu2430 Beans 单调队列 // // 题目意思: // 求一个sum%p<=k的max(sum/p) // // 结题报告: // 技巧,先求出前缀和,并记录前i项对p取余的值记为x,并记下位置pos // 按照先按x从小到大,如果x相同按pos从小到大排序.这样,问题就转换为 // 求一个最小的pos使得pos到i的值最大. // // 单调队列里面保持的就是对于当前的i最小的pos值(满足pos到i区间的sum是满足条件的) // 因为数组递增,这样求得的sum一定是最大的

hdu3530 Subsequence 单调队列

// hdu3530 Subsequence 单调队列 // 题目大意:找到一个最大的子串,使得子串区间内最大值和最小值的差 // 在low和up范围内,串的规模10w. // 解题思路: // 单调队列,单调队列可以保留i位置之前的最大值和最小值的下标,有了这些 // 则,每次我们比较两个队列的队头,看差值是否大于up,(因为它是到i位置最大 // 的差值,其他值不可能比i还要大.) // 如果大于,则将两个对头靠前的那个丢掉,即出队,再比较对头,并且记录下 // 出队的位置下标,(因为此时出

单调队列优化dp题目

附一链接,大多题型里面有,再附两题:https://blog.csdn.net/hjf1201/article/details/78729320 1.绿色通道 题目描述 Description <思远高考绿色通道>(Green Passage, GP)是唐山一中常用的练习册之一,其题量之大深受lsz等许多oiers的痛恨,其中又以数学绿色通道为最.2007年某月某日,soon-if (数学课代表),又一次宣布收这本作业,而lsz还一点也没有写-- 高二数学<绿色通道>总共有n道题目

单调队列/单调栈入门详解+题目推荐

以前一直以为这两个是很高级的东西,这段时间用到了才开始学,发现实际上非常简单 下面我们以单调队列为例进行讲解,单调栈自行类比 顾名思义 单调队列这个名字就指明了它的性质--单调性 我们来看一道例题--滑动窗口 题面在此不再赘述,大意就是有一个长度为\(n\)的数列,一个长度为\(k\)的窗口,输出窗口位于每个位置下的下的最大最小值 嗯,题目很好理解,st表或者线段树过的先别说话,我们来看看另一种方法 我们维护一个长度为k的队列,使得队列的开头为答案,那么我们每次只需要输出开头就好了.这个想法很好

部分单调队列优化 DP 题目解析

这里专门放一些单调队列优化 DP 的题目,并加上简要解析. Luogu P1725 琪露诺 易得转移方程为 $$f_i=\max_{j\,=\,\max(i-R,\;0)}^{i-L}f{_ j}+a_i\;(L \le i \le n)$$ 那么,其中 $\max$ 部分可以看成一段区间的最大值,用单调队列维护. 然后答案是 $$\max_{i\,=\,n-r+1}^{n} f_i$$ 时间复杂度 $O(n)$. 部分单调队列优化 DP 题目解析 原文地址:https://www.cnblog

hdu_5884_Sort(二分+单调队列)

题目链接:hdu_5884_Sort 题意: 有n个数,每个数有个值,现在你可以选择每次K个数合并,合并的消耗为这K个数的权值和,问在合并为只有1个数的时候,总消耗不超过T的情况下,最小的K是多少 题解: 首先要选满足条件的最小K,肯定会想到二分. 然后是如何来写这个check函数的问题 我们要贪心做到使消耗最小,首先我们将所有的数排序 然后对于每次的check的mid都取最小的mid个数来合并,然后把新产生的数扔进优先队列,直到最后只剩一个数. 不过这样的做法是n*(logn)2 ,常数写的小

[Vijos 1243]生产产品(单调队列优化Dp)

Description 在经过一段时间的经营后,dd_engi的OI商店不满足于从别的供货商那里购买产品放上货架,而要开始自己生产产品了!产品的生产需要M个步骤,每一个步骤都可以在N台机器中的任何一台完成,但生产的步骤必须严格按顺序执行.由于这N台机器的性能不同,它们完成每一个步骤的所需时间也不同.机器i完成第j个步骤的时间为T[i,j].把半成品从一台机器上搬到另一台机器上也需要一定的时间K.同时,为了保证安全和产品的质量,每台机器最多只能连续完成产品的L个步骤.也就是说,如果有一台机器连续完

单调队列

先放上luogu的题目链接--滑稽窗口 然后我们再来讲单调队列 单调队列是指这样一种队列:在队列中的元素为单调递增状态或单调递减状态. 例如1 2 3 4 5和9 2 1都是单调队列,但1 2 2 3 4和4 3 4 5就不是单调队列. 但普通队列明显是维持不了单调队列的性质的. 为了维持单调队列的单调性质,我们只好想一些方法.方法就是修改队列的性质.单调队列不仅队头可以出队,队尾也可以出队. 比如说有一个单调队列是 1 3 7 8 现在突然要从队尾进来一个6如果单纯的把6插进队尾的话,那这个队

codevs3327选择数字(单调队列优化)

3327 选择数字 时间限制: 1 s 空间限制: 256000 KB 题目等级 : 钻石 Diamond 题目描述 Description 给定一行n个非负整数a[1]..a[n].现在你可以选择其中若干个数,但不能有超过k个连续的数字被选择.你的任务是使得选出的数字的和最大. 输入描述 Input Description 第一行两个整数n,k 以下n行,每行一个整数表示a[i]. 输出描述 Output Description 输出一个值表示答案. 样例输入 Sample Input 5 2