P14555 [ROI 2013 Day1] 古老王朝

洛谷

考虑设置方便转移的状态。

范围很大,所以考虑能否搞出一维状态。

我们需要通过一个状态得到最近的 \(1\)\(2\) 的位置。

前面一位不是 \(1\) 就是 \(2\) 那么我们只需要记录 \(dp_{i,1/2}\) 表示前一位是 \(1\) 或者 \(2\) 而另一个数在位置 \(i\) 的情况最小结果。

转移时我们通过完整的连续段进行转移,需要判断中间这段是否可行,以及后面新产生的另外一个数字与前面是否可行。

对于中间这段连续段是否可行的条件,可以预处理后快速判断,显然对于每个状态满足此条件的区间左端点会不断向右,满足单调性。

而后面新产生的另外一个数字与前面是否可行这个条件同样是一个区间,但是其有最大值要求和最小值要求。只需要把距离达到最小要求的状态加入进单调队列,再从头部取出不满足最大值要求的和中间段要求的即可。

代码:

#include<bits/stdc++.h>
using namespace std;
int n,a[200005],m,l1,l2,r1,r2,dp1[200005],dp2[200005],pre1[200005],pre2[200005],p1[200005],p2[200005],head1,head2,tail1,tail2,nxt1[200005],nxt2[200005],ans[200005];
void getans(int op,int x){
	if(!x)return;
	int la=(op==1?nxt1[x]:nxt2[x]);
	for(int i=la+1;i<=x;i++)ans[i]=op;
	getans(3-op,la);
}
void add1(int i){
	while(head1<=tail1&&dp1[i]-i<=dp1[p1[tail1]]-p1[tail1])tail1--;
	p1[++tail1]=i;
}
void add2(int i){
	while(head2<=tail2&&dp2[i]-i<=dp2[p2[tail2]]-p2[tail2])tail2--;
	p2[++tail2]=i;
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++)cin>>a[i];
	cin>>m;
	int res=1e8,w=0;
	for(int tt=1;tt<=m;tt++){
		cin>>l1>>r1>>l2>>r2;
		for(int i=2;i<=n;i++){
			int d=a[i]-a[i-1];
			pre1[i]=(d>=l1&&d<=r1);
			pre2[i]=(d>=l2&&d<=r2);
		}
		for(int i=2;i<=n;i++)pre1[i]+=pre1[i-1],pre2[i]+=pre2[i-1];
		memset(dp1,0x3f,sizeof(dp1));
		memset(dp2,0x3f,sizeof(dp2));
		dp1[0]=dp2[0]=0;
		if(pre1[n]-pre1[1]==n-1)nxt1[n]=0,dp1[n]=n-1;
		if(pre2[n]-pre2[1]==n-1)nxt2[n]=0,dp2[n]=n-1;
		head1=head2=1;tail1=tail2=0;
		int w1=1,w2=1;
		for(int i=1;i<n;i++){
			if(pre1[i]-pre1[1]==i-1)if(i-1<dp1[i])dp1[i]=i-1,nxt1[i]=0;
			if(pre2[i]-pre2[1]==i-1)if(i-1<dp2[i])dp2[i]=i-1,nxt2[i]=0;
			
			while(w1<i&&a[i+1]-a[w1]>=l2)add2(w1++);
			while(head2<=tail2&&!(pre1[i]-pre1[p2[head2]+1]==i-p2[head2]-1&&a[i+1]-a[p2[head2]]<=r2))head2++;
			if(head2<=tail2)if(dp2[p2[head2]]+i-p2[head2]-1<dp1[i])dp1[i]=dp2[p2[head2]]+i-p2[head2]-1,nxt1[i]=p2[head2];
			
			while(w2<i&&a[i+1]-a[w2]>=l1)add1(w2++);
			while(head1<=tail1&&!(pre2[i]-pre2[p1[head1]+1]==i-p1[head1]-1&&a[i+1]-a[p1[head1]]<=r1))head1++;
			if(head1<=tail1)if(dp1[p1[head1]]+i-p1[head1]-1<dp2[i])dp2[i]=dp1[p1[head1]]+i-p1[head1]-1,nxt2[i]=p1[head1];
			
			if(pre1[n]-pre1[i+1]==n-i-1)if(dp1[n]>dp2[i]+n-i-1)dp1[n]=dp2[i]+n-i-1,nxt1[n]=i;
			if(pre2[n]-pre2[i+1]==n-i-1)if(dp2[n]>dp1[i]+n-i-1)dp2[n]=dp1[i]+n-i-1,nxt2[n]=i;
		}
		if(min(dp1[n],dp2[n])<res){
			res=min(dp1[n],dp2[n]);
			w=tt;
			if(dp1[n]<dp2[n])getans(1,n);
			else getans(2,n);
		}
	}
	if(res>n){
		cout<<0;
		return 0;
	}
	cout<<w<<' '<<res<<endl;
	for(int i=1;i<=n;i++)cout<<ans[i];
	return 0;
}
posted @ 2026-09-08 09:00  huhangqi  阅读(16)  评论(0)    收藏  举报