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

浙公网安备 33010602011771号