(easy version):node
題目連接:http://codeforces.com/contest/1296/problem/E1ios
題目一句話就是說,兩種顏色不一樣的字符能夠相互換位,spa
問,對這字符串用最多兩種顏色染色,而後通過有限次換位code
能夠變成字典序排序的順序。blog
思路:一個字符需不須要換位,應該是參照最後的字典序的順序,排序
那麼,咱們應該給字符串排序,再去思考問題。ci
咱們知道,若是str[now_i]的位置和排序後的位置不同,那就是須要換位。字符串
咱們還知道,若是str[now_i]的當前位置若是小於等於排序後的位置,get
說明str[now_i]會日後移動,以前應該是會多出(>=0)個字符,那麼咱們不妨string
讓str[now_i]不主動移動(標記‘0’),讓str[now_x]當前位置大於排序後位置的去向前主動移動(也必須向前移動)(標記‘1’),
那麼通過一些str[now_x]向前移動,str[now_i]會被動的回到排序後的位置,從而達到"YES"。
那什麼狀況是「NO」?
若是咱們標記的'1'字符組成的字符串出現了"ba",」bca」,就是說不知足非遞減性質,
那麼"ba",a是'1',b也是'1',就是說,a不可能到b前面,那也就是「NO」了,舉個樣例:
7
abcdedc
0000011
撇開這個樣例無論,若是出現了"ba",若是把要b換成'0',那麼以前本該屬於b位置的須要變成'1',
使得能夠和b轉位,可是被換成'1'的那個字符又致使'a'不能回到a本該屬於的位置,因此這個狀況是''NO"就證實成立了,也間接證實了"YES"狀況的正確性,因此方法猜測正確,以後的作法就只須要維護這個方法就行。
時間複雜度能夠是O(n)
1 #include <iostream> 2 #include <algorithm> 3 #include <string> 4 #include <queue> 5 #include <cstdio> 6 using namespace std; 7 8 struct Info{ 9 queue<int > index; 10 void pb(int x){ index.push(x); } 11 int loc(){ int x = index.front(); index.pop(); return x; } 12 }info[30];//存儲不一樣字符出現的位置 13 14 int main(){ 15 16 string str; 17 int a[500]; 18 int col[500];//顏色 19 int n; 20 cin >> n >> str; 21 for(int i = 0; i < n;++i) a[i] = str[i]-'a';//字符轉化爲數字 22 sort(a,a+n);//排序 23 for(int i = 0; i < n; ++i) info[a[i]].pb(i);//把該字符出現的位置記錄 24 char error[10] = "aa";//error[0]存儲的是不須要主動移動的字符最大是哪一個 25 //error[1]存儲的是須要主動移動的字符最大的是哪一個 26 for(int now = 0; now < n; ++now){//now表示當前位置 27 int after = info[str[now]-'a'].loc();//取一個該字符排序後的位置 28 if(now <= after){//當前位置小於等於排序後的位置,這裏有個特殊狀況, 29 //abcdedc① 30 //abccdde 31 //能夠看出第二個d雖然和排序後的位置同樣,可是他須要換位 32 if(str[now] >= error[0]){ 33 error[0] = str[now]; 34 col[now] = 0; 35 }else{ 36 col[now] = 1; 37 if(str[now] > error[1]) error[1] = str[now];//①的狀況出現須要改變error[1]的字符 38 } 39 } 40 else{ 41 if(str[now] >= error[1]){ 42 col[now] = 1; 43 error[1] = str[now]; 44 }else{ 45 error[1] = '!'; break; 46 } 47 } 48 } 49 if(error[0] == '!' || error[1] == '!') cout << "NO\n"; 50 else{ 51 cout << "YES\n"; 52 for(int i = 0; i < n; ++i) cout << col[i]; 53 cout << endl; 54 } 55 56 return 0; 57 }
(hard version):
題目連接:http://codeforces.com/contest/1296/problem/E2
題目:E1說明了只能用兩種顏色去染色,如今是最少用幾種顏色去染色,能夠完成字典序排序。
思路:再次思考E1的證實狀況,若是該字符須要染成'1',那麼它們組成的字符串是「單調非遞減」的,
而'0'組成的字符串也是「單調非遞減」的。因而,咱們想到,能夠把這個題目抽象成一些數字組成一個序列,
問你該序列最少能夠分紅幾個知足性質「非單調遞減」的集合,也就是幾種顏色了。
那麼E2題目就變得簡單了,E1也能夠不那麼複雜的寫了。
最多26個字符,也就是最多26個集合,那麼 時間複雜度是O(26*n)。
這裏有個細節,咱們須要充分利用字符之間的間隔,舉個例子:
abacd...
先分紅兩個集合 :ab ac,應該把d放在"ac"的後面,這樣才能充分能利用字符之間的間隔,知足最少顏色。
1 #include <iostream> 2 #include <vector> 3 #include <string> 4 #include <algorithm> 5 using namespace std; 6 7 const int N = (int)2e5+100; 8 struct node{ 9 int index; 10 char ch; 11 }; 12 int col = 0;//集合數 13 string str;//每一個集合最後的字符 14 int ans[N]; 15 16 int main(){ 17 18 ios::sync_with_stdio(false); 19 cin.tie(0); cout.tie(0); 20 int n; 21 char ch,max_ch,which_col,len,tmp_ch,now_ch; 22 cin >> n; 23 for(int i = 0; i < n; ++i){ 24 cin >> ch; 25 which_col = -1;//選哪一種顏色 26 tmp_ch = 'A'; 27 for(int j = 0; j < col; ++j){ 28 now_ch = str[j]; 29 //選col個集合中最後字符小於等於ch且最接近ch的 30 if(now_ch <= ch){ 31 if(now_ch > tmp_ch){ 32 tmp_ch = now_ch; 33 which_col = j; 34 } 35 } 36 } 37 if(which_col != -1){ 38 str[which_col] = ch; 39 ans[i] = which_col+1; 40 } 41 else{ 42 //須要新加一種顏色 43 str += ch; 44 ++col; 45 ans[i] = col; 46 } 47 } 48 49 cout << col << endl; 50 cout << ans[0]; 51 for(int i = 1; i < n; ++i) cout << ' ' << ans[i]; 52 cout << endl; 53 54 55 return 0; 56 }