单调队列

滑动窗口

这个是板子,没啥可说的

代码

#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];
}

posted @ 2023-10-07 16:40  jt0007  阅读(8)  评论(0)    收藏  举报