双栈模拟队列

使用情况:

可以使用双指针,但是这道题目如果带删除并不好实现,这时可以考虑用两个栈模拟队列解决问题。

时间复杂度与普通的双指针没有区别,但是每一个值需要存储一个可能很大的状态,比如一个完整的背包,导致空间复杂度可能会比较大

具体原理就是用栈来模拟队列,加入时用一个栈,每个加入的值记录的状态都需要继承转移上一次的栈顶状态,删除时如果另一个栈删完了,把原栈的值全部加入新栈,如何转移同上。

这种双指针的缺陷在于需要满足状态符合结合律,否则在查询时将两个栈栈顶进行处理会产生问题(暂时还想不到常见例子)

板子+板子题目

Integers Have Friends

作差维护gcd即可

#include<bits/stdc++.h>
#define int long long
using namespace std;
int t,n,a[200005],d[200005];
int gcd(int x,int y){
	if(!y)return x;
	return gcd(y,x%y);
}
struct Q{
	int top1,top2;
	pair<int,int> st1[200005],st2[200005];
	void push(int x){
		if(!top2)st2[++top2]={x,d[x]};
		else {
			int tmp=gcd(d[x],st2[top2].second);
			st2[++top2]={x,tmp};
		}
	}
	void pop(){
		if(top1){
			top1--;
			return;
		}
		while(top2){
			if(!top1)st1[++top1]={st2[top2].first,d[st2[top2].first]};
			else {
				int tmp=gcd(d[st2[top2].first],st1[top1].second);
				st1[++top1]={st2[top2].first,tmp};
			}
			top2--;
		}
		top1--;
	}
	int check(){
		if(!top2)return st1[top1].second;
		if(!top1)return st2[top2].second;
		return gcd(st1[top1].second,st2[top2].second);
	}
}q;
signed main(){
	cin>>t;
	while(t--){
		q.top1=q.top2=0;
		cin>>n;
		for(int i=1;i<=n;i++)cin>>a[i];
		for(int i=1;i<n;i++)d[i]=abs(a[i+1]-a[i]);
		int l=1,ans=0;
		for(int i=1;i<n;i++){
			q.push(i);
			while(q.check()==1)q.pop(),l++;
			ans=max(ans,i-l+2);
		}
		cout<<ans<<endl;
	}
	return 0;
}

Array Stabilization (GCD version)

还是维护gcd

#include<bits/stdc++.h>
#define int long long
using namespace std;
int t,n,a[200005];
int gcd(int x,int y){
	if(!y)return x;
	return gcd(y,x%y);
}
struct Q{
	int top1,top2;
	pair<int,int> st1[200005],st2[200005];
	void push(int x){
		if(!top2)st2[++top2]={x,a[x]};
		else {
			int tmp=gcd(a[x],st2[top2].second);
			st2[++top2]={x,tmp};
		}
	}
	void pop(){
		if(top1){
			top1--;
			return;
		}
		while(top2){
			if(!top1)st1[++top1]={st2[top2].first,a[st2[top2].first]};
			else {
				int tmp=gcd(a[st2[top2].first],st1[top1].second);
				st1[++top1]={st2[top2].first,tmp};
			}
			top2--;
		}
		top1--;
	}
	int check(){
		if(!top2)return st1[top1].second;
		if(!top1)return st2[top2].second;
		return gcd(st1[top1].second,st2[top2].second);
	}
}q;
signed main(){
	cin>>t;
	while(t--){
		q.top1=q.top2=0;
		cin>>n;
		for(int i=1;i<=n;i++)cin>>a[i];
		int tmp=a[1];
		for(int i=1;i<=n;i++)tmp=gcd(tmp,a[i]);
		int r=2*n,ans=0;
		for(int i=n;i>=1;i--)q.push(i);
		for(int i=n;i>=1;i--){
			q.push(i);
			while(q.check()==tmp)q.pop(),r--;
			ans=max(ans,r-i+1);
		}
		cout<<ans<<endl;
	}
	return 0;
}

小 ω 的仙人掌

只要胆子大,空间开的下

直接双栈双指针内维护一个背包即可

#include<bits/stdc++.h>
using namespace std;
int s,w,k,a[10005],b[10005];
struct BG{
	int c[5005];
	BG(){
		memset(c,0x3f,sizeof(c));
		c[0]=0;
	}
	void clear(){
		memset(c,0x3f,sizeof(c));
		c[0]=0;
	}
	void update(int x,int y){
		for(int i=w;i>=x;i--)c[i]=min(c[i],c[i-x]+y);
	}
	bool friend operator+(BG a,BG b){
		for(int i=0;i<=w;i++)if(a.c[i]+b.c[w-i]<=k)return true;
		return false;
	}
}dp[10005];
struct Q{
	int top1,top2,st1[10005],st2[10005];
	void push(int x){
		if(!top2)st2[++top2]=x,dp[x].update(a[x],b[x]);
		else {
			dp[x]=dp[st2[top2]];
			dp[x].update(a[x],b[x]);
			st2[++top2]=x;
		}
	}
	void pop(){
		if(top1){
			top1--;
			return;
		}
		while(top2){
			if(!top1){
				st1[++top1]=st2[top2];
				dp[st2[top2]].clear();
				dp[st2[top2]].update(a[st2[top2]],b[st2[top2]]);
			}
			else {
				dp[st2[top2]]=dp[st1[top1]];
				dp[st2[top2]].update(a[st2[top2]],b[st2[top2]]);
				st1[++top1]=st2[top2];
			}
			top2--;
		}
		top1--;
	}
	bool check(){
		if(!top2)return dp[st1[top1]].c[w]<=k;
		if(!top1)return dp[st2[top2]].c[w]<=k;
		return dp[st1[top1]]+dp[st2[top2]];
	}
}q;
signed main(){
	cin>>s>>w>>k;
	for(int i=1;i<=s;i++)cin>>a[i]>>b[i];
	int ans=1e9;
	int l=0;
	for(int i=1;i<=s;i++){
		q.push(i);
		while(q.check())q.pop(),l++;
		if(l)ans=min(ans,i-l+1);
	}
	if(ans>s)cout<<-1;
	else cout<<ans;
	return 0;
}

棋盘

用双栈模拟队列的思路进行dp,因为是队列,需要有加入和删除操作,也可以想到使用双栈模拟队列的方式

代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
int read(){
	char c=getchar();int x=0;bool f=0;
	while(c>'9'||c<'0'){
		if(c=='-')f=1;
		c=getchar();
	}
	while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
	if(f)return -x;
	return x;
}
int n,q,id;
char op[10],s[100005][25];
const int mod=998244353;
int p1[100005],top1,p2[100005],top2,dp[2][100005][21][21];
signed main(){
	freopen("chess.in","r",stdin);
	freopen("chess.out","w",stdout);
	n=read(),q=read();
	int head=1,tail=0,mid=0;
	while(q--){
		scanf("%s",op);
		if(op[0]=='A'){
			tail++;
			scanf("%s",s[tail]+1);
			if(head==tail){
				mid=tail;
				memset(dp[0][mid],0,sizeof(dp[0][mid]));
				memset(dp[1][mid],0,sizeof(dp[1][mid]));
				for(int i=1;i<=n;i++)dp[0][mid][i][i]=1;
			}
			else if(tail==mid+1)for(int i=1;i<=n;i++)dp[0][tail][i][i]=1;
			else {
				if(tail==mid+2)for(int i=1;i<=n;i++)dp[1][tail][i][i]=1;
				for(int i=1;i<=n;i++){
					for(int j=1;j<=n;j++){
						if(tail-1>mid){
							if(j<=n-2){
								dp[0][tail][i][j]=(dp[0][tail][i][j]+dp[0][tail-1][i][j+2])%mod;
								dp[1][tail][i][j]=(dp[1][tail][i][j]+dp[1][tail-1][i][j+2])%mod;
							}
							if(j>2){
								dp[0][tail][i][j]=(dp[0][tail][i][j]+dp[0][tail-1][i][j-2])%mod;
								dp[1][tail][i][j]=(dp[1][tail][i][j]+dp[1][tail-1][i][j-2])%mod;
							}
						}
						if(tail-2>mid){
							if(j<=n-1){
								dp[0][tail][i][j]=(dp[0][tail][i][j]+dp[0][tail-2][i][j+1])%mod;
								dp[1][tail][i][j]=(dp[1][tail][i][j]+dp[1][tail-2][i][j+1])%mod;
							}
							if(j>1){
								dp[0][tail][i][j]=(dp[0][tail][i][j]+dp[0][tail-2][i][j-1])%mod;
								dp[1][tail][i][j]=(dp[1][tail][i][j]+dp[1][tail-2][i][j-1])%mod;
							}
						}
					}
				}
			}
			for(int i=1;i<=n;i++)if(s[tail][i]=='#')for(int j=1;j<=n;j++)dp[1][tail][j][i]=dp[0][tail][j][i]=0;
		}
		else if(op[0]=='D'){
			head++;
			if(head>mid&&head<=tail){
				mid=tail;
				for(int i=head;i<=tail;i++){
					memset(dp[0][i],0,sizeof(dp[0][i]));
					memset(dp[1][i],0,sizeof(dp[1][i]));	
				}
				for(int i=1;i<=n;i++)dp[0][tail][i][i]=dp[1][tail-1][i][i]=1;
				for(int i=tail;i>=head;i--){
					for(int j=1;j<=n;j++){
						for(int k=1;k<=n;k++){
							if(i+1<=tail){
								if(k+2<=n){
									dp[0][i][j][k]=(dp[0][i][j][k]+dp[0][i+1][j][k+2])%mod;
									dp[1][i][j][k]=(dp[1][i][j][k]+dp[1][i+1][j][k+2])%mod;
								}
								if(k>2){
									dp[0][i][j][k]=(dp[0][i][j][k]+dp[0][i+1][j][k-2])%mod;
									dp[1][i][j][k]=(dp[1][i][j][k]+dp[1][i+1][j][k-2])%mod;
								}
							}
							if(i+2<=tail){
								if(k+1<=n){
									dp[0][i][j][k]=(dp[0][i][j][k]+dp[0][i+2][j][k+1])%mod;
									dp[1][i][j][k]=(dp[1][i][j][k]+dp[1][i+2][j][k+1])%mod;
								}
								if(k>1){
									dp[0][i][j][k]=(dp[0][i][j][k]+dp[0][i+2][j][k-1])%mod;
									dp[1][i][j][k]=(dp[1][i][j][k]+dp[1][i+2][j][k-1])%mod;
								}
							}
						}
					}
					for(int j=1;j<=n;j++)if(s[i][j]=='#')for(int k=1;k<=n;k++)dp[0][i][k][j]=dp[1][i][k][j]=0;
				}
			}
		}
		else {
			int x=read(),y=read();
			if(head>tail)puts("0");
			else if(tail==mid)printf("%lld\n",dp[0][head][y][x]);
			else {
				int ans=0;
				for(int i=1;i<=n;i++){
					if(i+2<=n)ans=(ans+dp[0][head][i][x]*dp[0][tail][i+2][y])%mod;
					if(i>2)ans=(ans+dp[0][head][i][x]*dp[0][tail][i-2][y])%mod;
					if(i+1<=n){
						ans=(ans+dp[0][head][i][x]*dp[1][tail][i+1][y])%mod;
						ans=(ans+dp[1][head][i][x]*dp[0][tail][i+1][y])%mod;
					}
					if(i>1){
						ans=(ans+dp[1][head][i][x]*dp[0][tail][i-1][y])%mod;
						ans=(ans+dp[0][head][i][x]*dp[1][tail][i-1][y])%mod;
					}
				}
				printf("%lld\n",ans);
			}
		}
	}
	return 0;
}
posted @ 2025-11-28 10:05  huhangqi  阅读(0)  评论(0)    收藏  举报
/*
*/