AT_arc195_d [ARC195D] Swap and Erase[Hard+]

前言

题目传送门

题意

分两种操作:交换相邻元素或者消掉 \(A\) 数组的最长相同前缀。每种操作都会产生 \(1\) 的代价。

现在问你花最小代价使 \(A\) 消完。

解题思路

首先我们观察到可以先交换再消,考虑怎么交换可以使答案更优。

因为肯定不会出现反复横跳的情况,所以假设所有点都往左交换,于是考虑交换 \(i,i-1\) 会产生什么贡献,分类讨论一下。如果 \(a_{i-2} = a_{i}\),则可以让 \(i,i-2\) 一起被消,可以产生 \(1\) 的贡献,如果 \(a_{i+1} = a_{i-1}\),那也会产生 \(1\) 的贡献,但是交换就会产生 \(1\) 的代价。我们看看如果交换 \(i,i-2\),则等价于将 \(i-1,i-2\) 这个整体与 \(i\) 交换,产生的贡献最多跟交换一个产生的最多贡献是一样的。

所以,形式化地总结来说,一个点的移动至多只会另两个点产生贡献,且每个点只能产生 \(1\) 的贡献(即一个点不能因为重复交换而重复产生贡献),多次的交换操作可以等价于讲一个点与一个区间交换,这样产生的贡献至多为 \(2\),所以每个点至多交换一次肯定是最优的。

这样就大大消减了状态数,于是我们记 \(f_{i,0/1}\) 表示 \(i\) 这位数是否与 \(i-1\) 交换的最小代价,不交换的代价可以由 \(i-1\) 交换或不交换的状态转移来,而交换的代价只能由 \(i-2\) 交换和不交换的状态转移来(如果 \(i-1\)\(i\) 都交换的话,等价于 \(i-2\) 向右交换了 \(2\) 位,由推出的性质可知这是不优的)。

转移细节看看代码吧,注意点边界情况:

Code

#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define uint unsigned int
#define i128 __int128
#define ld long double
#define fir first
#define sec second
#define pii pair<int,int>
#define pll pair<ll,ll>
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
#define lowbit(x) (x&-x)
using namespace std;
namespace FastIO{ //这是禁忌秘术
	const int Size=1<<21;
	char ibuf[Size],obuf[Size],*p1=ibuf,*p2=ibuf,*p3=obuf;
	#define getchar() (p1==p2&&(p2=(p1=ibuf)+fread(ibuf,1,Size,stdin),p1==p2)?EOF:*p1++)
	#define putchar(x) (p3-obuf<Size?(*p3++=(x)):(fwrite(obuf,1,p3-obuf,stdout),p3=obuf,*p3++=(x)))
	inline void flush(){if(p3>obuf) fwrite(obuf,1,p3-obuf,stdout),p3=obuf;}
	template<class T>
	T read(T&x){
		x=0;bool f=false;char ch=getchar();
		while(!isdigit(ch)) f|=!(ch^'-'),ch=getchar();
		while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch&0xF),ch=getchar();
		x=(f?-x:x);return x;
	}template<class T>
	int reads(T*s){
		char ch=getchar();int len=0;
		while(ch==' '||ch=='\n'||ch=='\r') ch=getchar();
		while(ch!=' '&&ch!='\n'&&ch!=EOF&&ch!='\r') s[len++]=ch,ch=getchar();
		s[len]='\0';return len;
	}template<class T>
	T readd(T&x){
		x=0;bool f=false;char ch=getchar();
		while(!isdigit(ch)) f|=!(ch^'-'),ch=getchar();
		while(isdigit(ch)) x=x*10+(ch&0xF),ch=getchar();
		if(ch=='.'){ch=getchar();T d=1;while(isdigit(ch)) d*=0.1,x+=d*(ch&0xF),ch=getchar();}
		x=(f?-x:x);return x;
	}template<class T>
	void write(T x,char ch=' '){
		if(x<0) putchar('-'),x=-x;
		char tmp[41];int cnt=0;
		while(x>9) tmp[cnt++]=x%10+'0',x/=10;tmp[cnt++]=x+'0';
		while(cnt) putchar(tmp[--cnt]);putchar(ch);
	}template<class T>
	void writes(T x,int l=0,int r=-1){
		if(~r){for(int i=l;i<=r;i++) putchar(x[i]);}
		else{for(int i=l;x[i];i++) putchar(x[i]);}
	}template<class T>
	void writed(T x,int p=6,char ch=' '){
		if(x<0) putchar('-'),x=-x;
		T d=0.5;for(int i=0;i<p;i++) d*=0.1;x+=d;
		i128 g=(i128)(x);p?write(g,'.'):write(g,ch);
		if(p){T f=x-g;for(int i=0,d;i<p;i++) f*=10,d=(int)(f),putchar(d+'0'),f-=d;putchar(ch);}
	}
}
using namespace FastIO;
const int N=2e5+10,INF=0x3f3f3f3f;
int dp[N][2],n,m,T;
ll a[N];
void solve(int l,int r){
	dp[l-1][0]=0,dp[l-1][1]=INF;
	for(int i=l;i<=r;i++){
		dp[i][0]=dp[i-1][0]+(a[i]!=a[i-1]||i==l);
		dp[i][1]=INF;
		if(i>l) dp[i][0]=min(dp[i][0],dp[i-1][1]+(a[i]!=a[i-2]||i==l+1));
		if(i>l+1){
			dp[i][1]=dp[i-2][0]+(a[i]!=a[i-1])+(a[i]!=a[i-2])+1;
			if(i>3) dp[i][1]=min(dp[i][1],dp[i-2][1]+(a[i]!=a[i-1])+(a[i]!=a[i-3])+1);
		}
	}
}
void work(){
	read(n);
	for(int i=1;i<=n;i++) read(a[i]);
	solve(1,n);
	write(min(dp[n][0],dp[n][1]),'\n');
}
int main(){
//	freopen("swap.in","r",stdin);
//	freopen("swap.out","w",stdout);
	read(T);
	while(T--) work();
	flush();
	return 0;
}
posted @ 2025-12-14 23:20  AstraeusGleam  阅读(0)  评论(0)    收藏  举报