通過做這道題學到了很多知識,還是很好的,用到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;
}