(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 }