首页 > 其他分享 >单调队列优化dp

单调队列优化dp

时间:2025-01-18 14:42:44浏览次数:1  
标签:队列 max int dp 转移 单调

一本通题解

T2:

再也不想碰这道题了。。。写了一下午。

我们先设状态 \(dp[i][j]\) 表示前i个刷匠,考虑了前 \(j\) 个木板后所获得的最大价值(\(j\) 个木板可以有空余)。

然后枚举前 \(i\) 个刷匠,枚举每一条木板。

对于一条木板可以此刷匠根本不刷,或不刷当前木板,状转方程:

\[dp[i][j]=max(dp[i-1][j],dp[i][j-1]) \]

还可以刷以这一块木板为结尾的连续一段区间,这个转移条件为 \(j>=s[i]\) 和 \(j-l[i]+1<=s[i]\),我们把这一段要刷的区间设为 \([k+1,j]\) 状转方程

\[dp[i][j]=\max^{k<s[i]}_{k=j-l[i]} \{dp[i-1][k]+p[i]*(j-k)\} \]

\(p[i]*j\) 是固定的我们可以把它提出来

\[dp[i][j]=p[i]*j+\max^{k<s[i]}_{k=j-l[i]} \{dp[i-1][k]-p[i]*k\} \]

后面这一堆我们可以用单调队列维护,注意到因为单调队列右端点是固定的 \(s[i]\),所以我们可以先预处理出单调队列然后维护单调队列的头即可。

注意一些边界条件特判。

T3:

比较巧妙的优化,因为注意到我们是从i的前k个dp数组中转化dp[i]的,所以单调队列来维护前k位dp最小值,但是,你会发现如果前面的高度小于此树高,就会带来1的贡献,但是它只有1啊,所以我们只需要让高度小的在单调队列前即可

注意:树高是严格小于

T4:

时隔许久,我终于来填单调队列这一道大坑了

现在看来也没有那么难

by the way,这道题题目描述错了,输入时b,t反了,原题为CF372C

首先我们枚举烟花,从时间从大到小的顺序,然后再枚举在哪个位置转移的话,就是从 \(t_i~t_{i-1}\) 这段时间能到这个位置的所有位置都可以转移到这,然后这个转移可以用单调队列优化

T5:

首先注意题目中的几个小细节:要先从0号节点出发,也就是我们需要手动添加一个距离为0,权值为0的节点,其次是可以在任意位置结束,就是只要存在dp值大于k就可以了

很明显这题一眼二分,然后我们根据二分出的g来确定单调队列的范围,然后转移即可

注:细节若一个点无法从原先的点转移过来,就把这个点的dp设为-inf

代码:

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5e5+5,inf=1e18;
int n,d,k,mx,q1,q2;
int u[N],w[N],q[N],dp[N];
void add(int x,int z){
    while(q1<=q2&&u[q[q1]]<z)  q1++;
    while(q1<=q2&&dp[q[q2]]<=dp[x])  q2--;
    if(u[x]<z)  return;
    q[++q2]=x;
}
bool check(int g){
    for(int i=0;i<=n;i++)  dp[i]=0,q[i]=0;
    dp[0]=0;
    u[0]=0;
    q1=1,q2=0;
    int l=max(d-g,1ll),r=d+g;
    for(int i=1,j=0;i<=n;i++){
        while(u[j]<=u[i]-l){
            add(j,u[i]-r);
            j++;
        }
        while(q1<=q2&&u[q[q1]]<u[i]-r)  q1++;
        if(q1>q2){
            dp[i]=-inf;
            continue;
        }
        dp[i]=dp[q[q1]]+w[i];
        if(dp[i]>=k)  return 1;
    }
    return 0;
}
signed main(){
    scanf("%lld%lld%lld",&n,&d,&k);
    for(int i=1;i<=n;i++){
        scanf("%lld%lld",&u[i],&w[i]);
        mx=max(u[i],mx);
    }
    int l=0,r=mx;
    while(l<r){
        int mid=(l+r)>>1;
        if(check(mid))  r=mid;
        else  l=mid+1;
    }
    printf("%lld",l);
}

T6:

本质上是单调栈,我们维护一个递增的单调栈,然后假如i元素被j元素弹出,说明i元素的一个边界为j元素,所以正反跑一遍单调栈,统计左右边界

T7:

板子题,然后记录一下从哪里转移过来的就好了

T8:

二分单调队列长度,板子

T9:

我们设 \(dp[i]\) 为 \((1,i)\) 不包含违禁词的最小减少量,然后我们设 \(f[i]\) 为以 \(i\) 结尾,不包含违禁词的区间的开头,注意:只有满足有单词以 \(i\) 结尾,才进行转移,所以转移就是 \(dp[i]=\max ^i_{k=f[i]}\{ dp[i-1]+a[i] \}\)

然后我们对每一个单词跑一遍kmp,然后预处理出 \(f[i]\) ,只有有值才进行转移,转移范围就是 \(f[i]\),用单调队列维护即可

T10:

毒瘤题,题解不可看

朴素dp: \(f_i=\min\{f_j+\max_{k=j+1}^i a_k\}\),\(j\) 满足 \(\sum^i_{j=x} a_x<m\)

我们先预处理对于每一个 \(i\) 的 \(j\) 的范围为 \(f_i\),然后对于这个范围我们可以维护一个单调递减的队列,这样就去掉了内层的 \(\max\) 限制,考虑如何拆掉第二层限制,我们观察 \(f_i\) 的性质,发现它是单调递增的,我们考虑我们的

代码:

点击查看代码
#include<bits/stdc++.h>
#define int long long
#define pii pair<int,int>
using namespace std;
const int N=1e5+5;
int n,m,q1,q2;
int a[N],sum[N],f[N],q[N],num[N],dp[N];
priority_queue<pii,vector<pii>,greater<pii> >mn,del;
signed main(){
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%lld",&a[i]);
        if(a[i]>m){
            printf("-1");
            return 0;
        }
    }
    f[0]=1;
    for(int i=1;i<=n;i++){
        sum[i]=sum[i-1]+a[i];
        f[i]=f[i-1];
        while(sum[i]>m){
            sum[i]-=a[f[i]];
            f[i]++;
        }
        // printf("%d ",f[i]);
    }
    // printf("\n");
    q1=1,q2=0;
    for(int i=1;i<=n;i++){
        while(q1<=q2&&q[q1]<f[i]){
            del.push({num[q[q1]],q[q1]});
            q1++;
        }
        while(q1<=q2&&a[q[q2]]<=a[i]){
            del.push({num[q[q2]],q[q2]});
            q2--;
        }
        q[++q2]=i;
        if(q1==q2)  num[i]=dp[f[i]-1]+a[i];
        else  num[i]=dp[q[q2-1]]+a[i];
        mn.push({num[i],i});
        del.push({num[q[q1]],q[q1]});
        num[q[q1]]=dp[f[i]-1]+a[q[q1]];
        mn.push({num[q[q1]],q[q1]});
        while(!del.empty()){
            if(del.top()!=mn.top())  break;
            del.pop(),mn.pop();
        }
        if(i!=1)  dp[i]=mn.top().first;
        else  dp[i]=a[i];
        // printf("%d %d %d\n",dp[i],num[i],mn.top().second);
        // for(int j=q1;j<=q2;j++){
        //     printf("%d ",q[j]);
        // }
        // printf("\n");
    }
    printf("%lld",dp[n]);
    return 0;
}

标签:队列,max,int,dp,转移,单调
From: https://www.cnblogs.com/zcxnb/p/18678450

相关文章

  • LCS(递归/记忆化/dp)
    题目链接:https://leetcode.cn/problems/longest-common-subsequence/TLE暴力递归+记忆化版本(基于字符串长度无优化版本)//注意text1[i1-1]==text2[i2-1]classSolution{public:intdp[1000][1000];intlongestCommonSubsequence(stringtext1,stringtext2){......
  • 漏洞预警 | WordPress Plugin Radio Player SSRF漏洞
    0x00漏洞编号CVE-2024-543850x01危险等级高危0x02漏洞概述WordPress插件RadioPlayer是一种简单而有效的解决方案,用于将实时流媒体音频添加到您的WordPress网站。0x03漏洞详情CVE-2024-54385漏洞类型:SSRF影响:获取敏感信息简述:RadioPlayer的/wp-admin/admin-......
  • 系统编程(进程通信--消息队列)
    消息队列概念:消息队列就是一个消息的链表,提供了一种由一个进程向另一个进程发送块数据的方法。另外,每一个数据块被看作有一个类型,而接收进程可以独立接收具有不同类型的数据块,在许多方面看来,消息队列类似于有名管道,但是却没有与打开与关闭管道的复杂关联。优点:1.通过发......
  • Kafka分布式消息队列
    一、概述kafka是一个分布式的基于发布/定义的消息队列(MessageQueue)通信处理同步处理客户端->数据库->发送短信->响应客户端异步处理客户端->数据库->发送短信放入MQ(直接响应客户端)消息队列的优势解耦:允许独立的处理两边处理过程,遵循接口约束即可可恢复性:当某......
  • 栈与队列(代码随想)
    目录1.理论分析1.1栈1.2队列2.用栈实现队列3.用队列实现栈算法公开课队列的基本操作!|LeetCode:225.用队列实现栈 (opensnewwindow)https://www.bilibili.com/video/BV1Fd4y1K7sm225.用队列实现栈-力扣(LeetCode)优化4.有效的括号5.删除字符串中的所有相邻重复......
  • 【韩国汉阳大学主办】第六届土木建筑及灾害防控国际学术会议暨第三届智慧城市建筑与基
    第六届土木建筑及灾害防控国际学术会议暨第三届智慧城市建筑与基础设施耐久性国际学术会议(CADPC&DuraBI2025)20256thInternationalConferenceonCivil,ArchitectureandDisasterPreventionandControl&3rdInternationalConferenceonDurabilityofBuildinga......
  • 云消息队列 Kafka 版 V3 系列荣获信通院“云原生技术创新标杆案例”
    2024年12月24日,由中国信息通信研究院(以下简称“中国信通院”)主办的“2025中国信通院深度观察报告会:算力互联网分论坛”,在北京隆重召开。本次论坛以“算力互联网新质生产力”为主题,全面展示中国信通院在算力互联网产业领域的研究、实践与业界共识,与产业先行者共同探索算力互......
  • 斜率优化DP
    斜率优化DP例题HNOI2008玩具装箱朴素dp设\(dp_i\)表示前\(i\)个物品,分若干段的最小代价。状态转移方程为:\[dp_{i}=\min_{j<i}\left\{dp_{j}+\left(i-(j+1)+s_{i}-s_{j}-L\right)^{2}\right\}=\min_{j<i}\left\{dp_{j}+\left(s_{i}-s_{j}+i-j-1-L\right)^{2}\right\}......
  • 三大主流国际课程IBDP、AP、A-Level的区别是什么?-季遇教育
      最近咨询季遇老师的有不少孩子就读双轨制的学校的家长,还有很多想要体制内转轨的家长,都会问到如何选择合适的国际课程。今天就给大家介绍一下三大主流课程的区别!  IB课程  IB一共分为四个学段:IBPYP(小学)、IBMYP(初中)、IBDP(高中)、IBCP(职业教育)四个学段,其中IBDP......
  • CSP2025 - 树形 DP
    CSP2025-树形DPT1「MXOIRound1」城市这个“树上两点距离之和”很典,让我们想到换根DP。首先求出\(\text{siz}_u\)和\(d_u\),分别表示子树\(u\)的大小和子树所有点到\(u\)的距离之和。接下来求出整棵树的所有点到\(\boldsymbolu\)的距离之和。考虑用\(d_u\)......