题解 P6116 [JOI 2019 Final]たのしいたのしいたのしい家庭菜園

· · 题解

CYJian 学长的 NOIP2020 模拟赛题,只有题面被魔改了(不过也是搬花盆)。但是蒟蒻考场只会做特殊性质 QwQ。

题意

给定一个由 R,G,Y 组成的,长度为 n 的字符串,每次只能交换相邻两个字符,问最少操作几次,能使相邻两个字符不同。若无解,输出 -1

Solution

$N\leq 15$ 枚举末状态即可。 $20pts$: 考虑特殊性质的末状态只有两种:`RGRGRG` 和 `GRGRGR`。可以发现规律:答案为所有不在最终位置上的 `R` 与最近的不在位置上的 `G` 中间间隔数 $+1$ 之和。 $80pts$: $N\leq 60$ 不能再枚举了考虑,dp。 首先,能发现性质: 1. 当一种颜色的数量大于 $\frac{n}{2}$ 时无解。 2. 交换同种颜色无意义。 3. **假设按原字符串给每个字符编号,相同字符的内部顺序不变。** 令 $R\to0,G\to1,Y\to2$。 设 $f_{i,j,k,l,0/1/2}$ 表示前 $i$ 位中有 $j$ 个 $0$、$k$ 个 $1$、$l$ 个 $2$ 且第 $i$ 位为 $0/1/2$ 的最小交换次数。 以 $f_{i,j,k,l,0}$ 为例,由性质 3 可知,第 $i$ 位上的这个 $0$ 一定是原串的第 $j$ 个 $0$ 移过来的,如果我们能算出**此时**原串的第 $j$ 个 $0$ 的位置 $w$,那么转移就是 $f_{i,j,k,l,0}=\max(f_{i-1,j-1,k,l,1},f_{i-1,j-1,k,l,2})+(w-i)$。 考虑 $w$ 怎么求,首先找到原串中第 $j$ 个 $0$ 的位置 $p$,在状态 $f_{i,j,k,l,0}$ 时,共有 $k$ 个 $1$,$l$ 个 $2$,若 $p$ 之前有足够的 $1,2$ 那么第 $j$ 个 $0$ 的位置是不会变的,否则则需要把 $p$ 之后的 $1,2$ 前移,第 $j$ 个 $0$ 会被挤到更靠后的位置(可能要理解一下)。 我们记前 $i$ 位中有 $sum_{i,1}$ 个 $1$,$sum_{i,2} $ 个 $2$,则 $w=p+\max(0,k-sum_{p,1})+\max(0,l-sum_{p,2})$。 $100pts$: $N\leq 400$,上面的状态是 $O(n^4)$ 的,考虑优化:$l=i-j-k$ 可以优化掉一维,然后滚动数组可以滚掉一维。 ✿ヽ(°▽°)ノ✿完结撒花啦! ### Code ``` #include<bits/stdc++.h> using namespace std; const int N=405; int n,id; int pos[N][3],sum[N][3],c0,c1,c2; int f[2][N][N][3]; char s[N]; int main() { scanf("%d",&n); scanf("%s",s+1); for(int i=1;i<=n;i++) { if(s[i]=='R') pos[++c0][0]=i;//第 c0 个 0 的位置 if(s[i]=='G') pos[++c1][1]=i; if(s[i]=='Y') pos[++c2][2]=i; sum[i][0]=sum[i-1][0]+(s[i]=='R');//前 i 位 0 的数量 sum[i][1]=sum[i-1][1]+(s[i]=='G'); sum[i][2]=sum[i-1][2]+(s[i]=='Y'); } memset(f,0x7f,sizeof(f)); f[1][1][0][0]=pos[1][0]-1; f[1][0][1][1]=pos[1][1]-1; f[1][0][0][2]=pos[1][2]-1; for(int i=2;i<=n;i++) { id=(i&1)?1:0; for(int j=0;j<=c0;j++) { for(int k=0;k<=c1;k++) { if(i-j-k>c2) continue; if(j>0) { int p=pos[j][0]; int w=p+max(0,k-sum[p][1])+max(0,i-j-k-sum[p][2]); f[id][j][k][0]=min(f[id^1][j-1][k][1],f[id^1][j-1][k][2])+w-i; } if(k>0) { int p=pos[k][1]; int w=p+max(0,j-sum[p][0])+max(0,i-j-k-sum[p][2]); f[id][j][k][1]=min(f[id^1][j][k-1][0],f[id^1][j][k-1][2])+w-i; } if(i-j-k>0) { int p=pos[i-j-k][2]; int w=p+max(0,j-sum[p][0])+max(0,k-sum[p][1]); f[id][j][k][2]=min(f[id^1][j][k][0],f[id^1][j][k][1])+w-i; } } } memset(f[id^1],0x7f,sizeof(f[id^1])); } if(n&1) { int ans=min(min(f[1][c0][c1][0],f[1][c0][c1][1]),f[1][c0][c1][2]); printf("%d",(ans<1e9)?ans:-1); } else { int ans=min(min(f[0][c0][c1][0],f[0][c0][c1][1]),f[0][c0][c1][2]); printf("%d",(ans<1e9)?ans:-1); } return 0; } ```