2025.11.19 D 题解

好题好题,但是这个音标题目名还是太生艹了。


第一眼感觉很多,感觉能柯朵莉树,但是有专门卡的包。后来发现似乎是得 \(dp\) 一下再找性质,但是没 \(dp\) 出来。

考虑性质:

每个数只会被换一次。
证明:假如换两次,来回换肯定不优,向前/向后换没有本质区别,那么就剩下下述情况(一点解释:为什么 \(x\) 前面都是 \(y\) 呢?因为不是 \(y\) 劣得没边):
1. \(y,x,y,z\),将 \(x\) 向后换两次。换一次都不优。
2. \(y,x,y,x\),将 \(x\) 向后换两次。换两次显然不优。
3. \(y,x,y,y\),将 \(x\) 向后换两次。换两次显然不优。
\(Q.E.D.\)(略显草率)

那就很好 \(dp\) 了。设 \(f_{i,0/1}\) 表示第 \(i\) 个位置有没有和前一个位置交换,则有:

\[f_{i,0}=\min(f_{i-1,0}+[a_i\ne a_{i-1}],f_{i-1,1}+[a_i\ne a_{i-2}]) \]

\[f_{i,1}=\min(f_{i-2,0}+[a_i\ne a_{i-2}],f_{i-2,1}+[a_i\ne a_{i-3}])+[a_i\ne a_{i-1}]+1 \]

发现这个东西可以用 \(O(4^3)\) 矩阵乘法优化,考虑动态 \(dp\)。发现区间加只会改变 \(l,l+1,l+2,r+1,r+2,r+3\) 六个位置的矩阵;区间推平除了改变这六个位置,还会将 \([l+3,r]\) 内的矩阵修改成一模一样的,区间修改+打标记即可。由于 \(a_i\) 会动态变化,所以还需要用一个线段树记录当前的 \(a_i\)

时间复杂度 \(O(4^3q\log n)\)。注意前三个位置实际上无法用常规的矩阵表示,所以先大力 \(dp\) 出来这三个位置再说。

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int n,q,a[N],dp[5][2],zb;
int num[N<<2],tag[N<<2];
inline void buildd(int x,int l,int r){
	tag[x]=-1;if(l==r){num[x]=a[l];return;}
	int mid=(l+r)>>1;buildd(x<<1,l,mid);
	buildd(x<<1|1,mid+1,r);
}inline void downn(int x,int v){
	if(~tag[x]) tag[x]+=v;num[x]+=v;
}inline void downt(int x,int v){num[x]=tag[x]=v;}
inline void pushdown(int x){
	if(~tag[x]) downt(x<<1,tag[x]),downt(x<<1|1,tag[x]),tag[x]=-1;
	else downn(x<<1,num[x]),downn(x<<1|1,num[x]);num[x]=0;
}inline void add(int x,int l,int r,int L,int R,int v){
	if(L<=l&&r<=R) return downn(x,v);
	int mid=(l+r)>>1;pushdown(x);
	if(L<=mid) add(x<<1,l,mid,L,R,v);
	if(R>mid) add(x<<1|1,mid+1,r,L,R,v);
}inline void assign(int x,int l,int r,int L,int R,int v){
	if(L<=l&&r<=R) return downt(x,v);
	int mid=(l+r)>>1;pushdown(x);
	if(L<=mid) assign(x<<1,l,mid,L,R,v);
	if(R>mid) assign(x<<1|1,mid+1,r,L,R,v);
}inline int find(int x,int l,int r,int k){
	if(l==r) return num[x];
	int mid=(l+r)>>1;pushdown(x);
	if(k<=mid) return find(x<<1,l,mid,k);
	return find(x<<1|1,mid+1,r,k);
}inline int fd(int x){return x>=zb?find(1,1,n,x):-1;}
inline void solve(int l,int r){
	dp[0][0]=0,dp[0][1]=1e9,zb=l;
	for(int i=1;i+l-1<=r;i++){
		dp[i][0]=dp[i-1][0]+(fd(i+l-1)!=fd(i+l-2)),dp[i][1]=1e9;
		if(i>1) dp[i][0]=min(dp[i][0],dp[i-1][1]+(fd(i+l-1)!=fd(i+l-3)));
		if(i>2) dp[i][1]=dp[i-2][0]+(fd(i+l-1)!=fd(i+l-2))+(fd(i+l-1)!=fd(i+l-3))+1;
		if(i>3) dp[i][1]=min(dp[i][1],dp[i-2][1]+(fd(i+l-1)!=fd(i+l-2))+(fd(i+l-1)!=fd(i+l-4))+1);
	}
}struct matrix{int z[4][4];}sg[N<<2],zt[N],cc;int tg[N<<2];
inline matrix operator*(matrix x,matrix y){
	matrix z;memset(z.z,0x3f,sizeof(z.z));
	for(int i=0;i<4;i++) for(int j=0;j<4;j++)
		for(int k=0;k<4;k++) z.z[i][k]=min(z.z[i][k],x.z[i][j]+y.z[j][k]);
	return z;
}inline void gets(int id,int x){
	memset(sg[x].z,0x3f,sizeof(sg[x].z)),zb=0;
	int lsz=fd(id),lso=fd(id-1),lst=fd(id-2),lsh=fd(id-3);
	sg[x].z[0][0]=(lso!=lsz),sg[x].z[1][0]=(lst!=lsz);
	sg[x].z[2][1]=(lso!=lsz)+(lst!=lsz)+1,sg[x].z[0][2]=0;
	sg[x].z[3][1]=(lso!=lsz)+(lsh!=lsz)+1,sg[x].z[1][3]=0;
}inline void build(int x,int l,int r){
	if(l==r) return gets(l,x);
	int mid=(l+r)>>1;build(x<<1|1,mid+1,r);
	build(x<<1,l,mid),sg[x]=sg[x<<1]*sg[x<<1|1];
}inline void down(int x,int l,int r){tg[x]=1;sg[x]=zt[r-l];} 
inline void push_down(int x,int l,int r,int mid){
	if(tg[x]) down(x<<1,l,mid),down(x<<1|1,mid+1,r),tg[x]=0; 
}inline void ass(int x,int l,int r,int L,int R){
	if(L<=l&&r<=R) return down(x,l,r);
	int mid=(l+r)>>1;push_down(x,l,r,mid);
	if(L<=mid) ass(x<<1,l,mid,L,R);
	if(R>mid) ass(x<<1|1,mid+1,r,L,R);
	sg[x]=sg[x<<1]*sg[x<<1|1];
}inline void chg(int x,int l,int r,int k){
	if(k<4||k>n) return;
	if(l==r) return gets(l,x);
	int mid=(l+r)>>1;push_down(x,l,r,mid);
	if(k<=mid) chg(x<<1,l,mid,k);
	else chg(x<<1|1,mid+1,r,k);
	sg[x]=sg[x<<1]*sg[x<<1|1]; 
}inline void sum(int x,int l,int r,int L,int R,matrix &mt){
	if(L<=l&&r<=R){mt=mt*sg[x];return;}
	int mid=(l+r)>>1;push_down(x,l,r,mid);
	if(L<=mid) sum(x<<1,l,mid,L,R,mt);
	if(R>mid) sum(x<<1|1,mid+1,r,L,R,mt);
}int main(){
	freopen("swap.in","r",stdin);
	freopen("swap.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n>>q,dp[0][0]=0,dp[0][1]=1e9,a[0]=-1;
	for(int i=1;i<=n;i++) cin>>a[i];
	buildd(1,1,n);if(n>3) build(1,4,n);
	memset(zt[0].z,0x3f,sizeof(zt[0].z));
	zt[0].z[0][0]=zt[0].z[1][0]=0;
	zt[0].z[2][1]=zt[0].z[3][1]=1;
	zt[0].z[1][3]=zt[0].z[0][2]=0;
	for(int i=1;i<=n;i++) zt[i]=zt[i-1]*zt[0];
	memset(cc.z,0x3f,sizeof(cc.z));
	while(q--){
		int op,l,r,v;cin>>op>>l>>r;
		if(op==1){
			cin>>v,add(1,1,n,l,r,v);
			chg(1,4,n,l),chg(1,4,n,l+1),chg(1,4,n,l+2);
			chg(1,4,n,r+1),chg(1,4,n,r+2),chg(1,4,n,r+3);
		}else if(op==2){
			cin>>v,assign(1,1,n,l,r,v);
			if(r-l>=3) ass(1,4,n,l+3,r);
			chg(1,4,n,l),chg(1,4,n,l+1),chg(1,4,n,l+2);
			chg(1,4,n,r+1),chg(1,4,n,r+2),chg(1,4,n,r+3);
		}else{
			if(r-l>2){
				solve(l,l+2),cc.z[0][0]=dp[3][0],cc.z[0][1]=dp[3][1];
				cc.z[0][2]=dp[2][0],cc.z[0][3]=dp[2][1],sum(1,4,n,l+3,r,cc);
				cout<<min(cc.z[0][0],cc.z[0][1])<<"\n";
			}else solve(l,r),cout<<min(dp[r-l+1][0],dp[r-l+1][1])<<"\n";
		}
	}return 0;
}
posted @ 2025-11-20 21:47  white_tiger  阅读(0)  评论(0)    收藏  举报