通过做这道题学到了很多知识,还是很好的,用到Dilworth定理
解题思路:
- 就是给你一堆字母,ababcdba,最终让你排成aaabbbcd(字典序最小)
- 如果2个位置的字母涂的颜色不同,那么他们可以交换,问的是用最少的颜色进行涂色,我们最少需要多少种颜色, 而且将他们的位置的颜色标记出来。
- 这里用到Dilworth定理:不上升子序列的数目 == 最长下降子序列的长度 (反之亦然,如果想看正面的点上面的链接即可)
- 这个题简单的来说是找有多少个不下降子序列,也就是能划分多少个全序集(可以自己推一下,因为如果是不下降的他们的颜色也不会变,所以找全序集的个数)
- 然后就推理出找最长下降子序列的长度,但是这个题不同于导弹拦截(洛谷的,可以去查下),他还需要整上颜色。
- 那么我们可以将当前位置字母的颜色变为比他大一的字母的颜色+1,比如d c b a 这四个字母吧,他们的颜色分别是1,2,3,4 因为都要进行交换,所以我们让当前字母的颜色为上一个颜色 + 1。
- 然后我们要让小于等于这个字母的颜色都为当前的最大值(从小到大涂),例如 c a 吧,a的大一个的为b,但是b是0,所以a涂1,但是c也是涂成1的,所以显然是不对的所以我们将<= c 的字符的颜色都涂成当前的最大的(可以看代码理解下)
- 最终输出即可
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 200010;
int a[N];
int ans[N];
int main(){
int n;
scanf("%d",&n);
string st;
cin>>st;
int res = 0;
for (int i = 0; i < n; i++){
ans[i] = a[st[i] - 'a' + 1] + 1;
res = max(ans[i],res);
a[st[i]-'a'] = ans[i];
int mx = 0;
for (int j = 26; j >= 0; j--){
a[j] = max(mx,a[j]);
mx = a[j];
}
}
printf("%d\n",res);
for (int i = 0; i < n; i++){
printf("%d ",ans[i]);
}
puts("");
return 0;
}