1 条题解
-
0
自动搬运
来自洛谷,原作者为

tytyty
**搬运于
2025-08-24 22:17:34,当前版本为作者最后更新于2022-11-06 15:27:40,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
CYJian 学长的 NOIP2020 模拟赛题,只有题面被魔改了(不过也是搬花盆)。但是蒟蒻考场只会做特殊性质 QwQ。
题意
给定一个由
R,G,Y组成的,长度为 的字符串,每次只能交换相邻两个字符,问最少操作几次,能使相邻两个字符不同。若无解,输出-1。Solution
:
枚举末状态即可。
:
考虑特殊性质的末状态只有两种:
RGRGRG和GRGRGR。可以发现规律:答案为所有不在最终位置上的R与最近的不在位置上的G中间间隔数 之和。:
不能再枚举了考虑,dp。
首先,能发现性质:
-
当一种颜色的数量大于 时无解。
-
交换同种颜色无意义。
-
假设按原字符串给每个字符编号,相同字符的内部顺序不变。
令 。
设 表示前 位中有 个 、 个 、 个 且第 位为 的最小交换次数。
以 为例,由性质 3 可知,第 位上的这个 一定是原串的第 个 移过来的,如果我们能算出此时原串的第 个 的位置 ,那么转移就是 $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)$。
考虑 怎么求,首先找到原串中第 个 的位置 ,在状态 时,共有 个 , 个 ,若 之前有足够的 那么第 个 的位置是不会变的,否则则需要把 之后的 前移,第 个 会被挤到更靠后的位置(可能要理解一下)。
我们记前 位中有 个 , 个 ,则 。
:
,上面的状态是 的,考虑优化: 可以优化掉一维,然后滚动数组可以滚掉一维。
✿ヽ(°▽°)ノ✿完结撒花啦!
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; } -
- 1
信息
- ID
- 5136
- 时间
- 500ms
- 内存
- 1024MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者