单调队列
滑动窗口
这个是板子,没啥可说的
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=1e7+5;
int q1[maxn];
int q2[maxn];
int a[maxn];
int n,k;
int hdd1,tll1;
int hdd2,tll2;
void qmax(){
cout<<'\n';
hdd1=1,tll1=0;
for(int i=1;i<=n;i++){
while(hdd1<=tll1&&q1[hdd1]+k<=i) hdd1++;
while(hdd1<=tll1&&a[i]>a[q1[tll1]]) tll1--;
q1[++tll1]=i;
if(i>=k) cout<<a[q1[hdd1]]<<" ";
}
}
void qmin(){
hdd2=1,tll2=0;
for(int i=1;i<=n;i++){
while(hdd2<=tll2&&q2[hdd2]+k<=i) hdd2++;
while(hdd2<=tll2&&a[i]<q2[tll2]) tll2--;
q2[++tll2]=i;
if(i>=k) cout<<a[q2[hdd2]]<<" ";
}
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>k;
for(int i=1;i<=n;i++) cin>>a[i];
qmin();
qmax();
return 0;
}
粉刷木板
首先能想到一个朴素的dp,设\(f[i][j]\)表示前i个人选到了j块木板
已得到dp转移式\(f[i][j]=max(f[i-1][j],max(f[i][j],f[i-1][k]+p*(j-k)))\)
p*j可以看作定值,因为相当于是从不同的k转移
那么我们可以得到\(f[i][j]=max(,f[i][j],p*j+f[i-1][k]-p*k)\)
先用单调队列找出上次的k,然后判断其合法性
代码如下:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=2e4+5;
int n,m;
int f[maxn];
int x[maxn];
int q[maxn];
int w[maxn];
struct node{
int s,l,p;
friend bool operator < (node a,node b){
return a.s<b.s;
}
}a[maxn];
signed main(){
cin>>n>>m;
for(int i=1;i<=m;i++) cin>>a[i].l>>a[i].p>>a[i].s;
sort(a+1,a+1+m);
for(int k=1;k<=m;k++){
int s=a[k].s,p=a[k].p,l=a[k].l;
int minn=max((long long)0,s-l);
int maxx=min(n,s+l);
for(int i=minn;i<=maxx;i++){
x[i]=f[i]-p*i;
}
int h=1,t=0;
for(int i=minn;i<s;i++){
while(h<=t&&x[i]>=q[t]) t--;
q[++t]=x[i];
w[t]=i;
}
for(int i=s;i<=maxx;i++){
while(h<=t&&w[h]<i-l) h++;
if(h<=t) f[i]=max(f[i],q[h]+p*i);
}
for(int i=2;i<=n;i++){
f[i]=max(f[i],f[i-1]);
}
}
cout<<f[n];
}


浙公网安备 33010602011771号