单调队列优化dp
一本通题解
T2:
再也不想碰这道题了。。。写了一下午。
我们先设状态
然后枚举前
对于一条木板可以此刷匠根本不刷,或不刷当前木板,状转方程:
还可以刷以这一块木板为结尾的连续一段区间,这个转移条件为
后面这一堆我们可以用单调队列维护,注意到因为单调队列右端点是固定的
注意一些边界条件特判。
T3:
比较巧妙的优化,因为注意到我们是从i的前k个dp数组中转化dp[i]的,所以单调队列来维护前k位dp最小值,但是,你会发现如果前面的高度小于此树高,就会带来1的贡献,但是它只有1啊,所以我们只需要让高度小的在单调队列前即可
注意:树高是严格小于
T4:
时隔许久,我终于来填单调队列这一道大坑了
现在看来也没有那么难
by the way,这道题题目描述错了,输入时b,t反了,原题为CF372C
首先我们枚举烟花,从时间从小到大的顺序,然后再枚举在哪个位置转移的话,就是从
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:
注:这里默认有一个限制,位置0与位置n+1被选择
二分单调队列长度,板子
T9:
我们设
然后我们对每一个单词跑一遍kmp,然后预处理出
T10:
毒瘤题,题解不可看
朴素dp:
我们先预处理对于每一个
代码:
点击查看代码
#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;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!