[DP记录]AT4132 [ARC097C] Sorted and Sorted

command_block

2021-05-04 09:56:14

Personal

**题意** : 有 $2N$ 个球排成一列,其中有 $N$ 个黑球与 $N$ 个白球。把 $1$ 到 $N$ 这 $N$ 个数字分别写到 $N$ 个黑球上;白球亦然。 每次操作可以交换两个相邻的球。 使用尽量少的操作使得从左到右黑球,白球上的数字分别递增。回答这个最小的操作数。 $n\leq 2000$ ,时限$\texttt{2s}$。 ------------ 对于某组方案,记 $p_i$ 为在 $i$ 位置的球最后到达的位置,则交换的最小次数是 $p$ 的逆序对数。 也能发现, $p$ 的一个逆序对对应一对相对顺序改变的球。 黑球和白球内部的逆序对是常数,单独计算。于是只需最小化黑球和白球之间的““相对顺序改变的球对”。 接下来考虑 $\rm DP$。 记 $dp[i][j]$ 表示在最终序列中放置了写有 $1\sim i$ 的白球,写有 $1\sim j$ 的黑球,产生的“相对顺序改变的黑白球对”的数目的最小值。 转移显然,可见代码。复杂度 $O(n^2)$。 ```cpp #include<algorithm> #include<cstdio> #define MaxN 2050 using namespace std; const int INF=1000000000; int n,p0[MaxN],p1[MaxN],o0[MaxN<<1][MaxN],o1[MaxN<<1][MaxN],dp[MaxN][MaxN]; char op; int main() { scanf("%d",&n); int sav=0; for (int i=1,p;i<=n+n;i++){ scanf("%s%d",&op,&p); for (int k=1;k<=n;k++) {o0[i][k]=o0[i-1][k];o1[i][k]=o1[i-1][k];} if (op=='W'){ p0[p]=i;sav+=o0[i][n]-o0[i][p]; for (int k=p;k<=n;k++)o0[i][k]++; }else { p1[p]=i;sav+=o1[i][n]-o1[i][p]; for (int k=p;k<=n;k++)o1[i][k]++; } } for (int i=0;i<=n;i++) for (int j=0;j<=n;j++) dp[i][j]=INF; dp[0][0]=0; for (int i=0;i<=n;i++) for (int j=0;j<=n;j++){ if (i>0)dp[i][j]=min(dp[i][j],dp[i-1][j]+o1[n+n][j]-o1[p0[i]][j]); if (j>0)dp[i][j]=min(dp[i][j],dp[i][j-1]+o0[n+n][i]-o0[p1[j]][i]); } printf("%d",sav+dp[n][n]); return 0; } ```