AT_arc097_e

套路题。想要做类似的还可以做做 P6116。

对于不断交换两个数的操作,容易发现确定开始位置 ss 和最终位置 tt,操作次数固定为 st|s-t|。所以可以考虑对答案序列进行 dp。

容易想到设 dpi,jdp_{i,j} 为当前已经放好了前 ii 个白色和 jj 个黑色,最少需要多少次操作。则有状态转移方程:

dpi,j=min(dpi1,j+pos(i,0)(i+j),dpi,j1+pos(j,1)(i+j))dp_{i,j}=\min(dp_{i-1,j}+pos(i,0)-(i+j),dp_{i,j-1}+pos(j,1)-(i+j))

其中 pos(i,0/1)pos(i,0/1) 表示第 ii 小的白/黑色球进行前面操作后坐在的位置。

然后观察此方程是否有后效性。容易发现,当前面的数固定时,pos(i,0/1)pos(i,0/1) 也是固定的。故方程无后效性。

进一步地,可以将 pos(x,0/1)pos(x,0/1) 拆成其初始位置再分别加上移到它前面的黑/白球的数量。O(n2)O(n^2) 预处理。最后 O(n2)O(n^2) dp 即可。

code:

int n,m,e[N],c[N],d[N][2],cst[N][N][2],dp[N][N];
void Yorushika(){
	scanf("%d",&n);
	rep(i,1,n*2){
		char op[3];
		int x;
		scanf("%s%d",op,&x);
		c[i]=op[0]=='B';
		e[i]=x;
		d[x][c[i]]=i;
	}
	rep(i,1,n){
		rep(j,1,n*2){
			cst[j][i][0]=cst[j][i-1][0];
			cst[j][i][1]=cst[j][i-1][1];
		}
		rep(j,1,d[i][0]){
			cst[j][i][0]++;
		}
		rep(j,1,d[i][1]){
			cst[j][i][1]++;
		}
	}
	mems(dp,0x3f);
	dp[0][0]=0;
	rep(i,1,n*2){
		rep(j,max(i-n,0),min(i,n)){
			int k=i-j;
			if(j)
				dp[j][k]=min(dp[j][k],dp[j-1][k]+d[j][0]+cst[d[j][0]][j-1][0]+cst[d[j][0]][k][1]-i);
			if(k)
				dp[j][k]=min(dp[j][k],dp[j][k-1]+d[k][1]+cst[d[k][1]][k-1][1]+cst[d[k][1]][j][0]-i);
		}
	}
	printf("%d\n",dp[n][n]);
}
signed main(){
	int t=1;
	//	scanf("%d",&t);
	while(t--)
		Yorushika();
}