[cf797c]Minimal string(贪心+模拟)
题意:
给出了字符串s的内容,字符串t,u初始默认为空,允许做两种操作:
1、把s字符串第一个字符转移到t字符串最后
2、把t字符串最后一个字符转移到u字符串最后
最后要求s、t字符串都为空,问u字符串字典序最小能是多少。
解题关键:
主要就是贪心,按字典序,每贪心完一个字母,往前回溯一次。
1、hash一下每个字母出现的次数,然后贪心选择字典序最小的即可。
2、预处理每个位置能达到的最小的字母,然后贪心。tmp一定是一个单调不减的数组。
3、小于等于而不是等于的原因是abacd这种情况。
反思:
1、这种看似简单的模拟题一定要搞明白,自己写一下。类似于栈混洗。
2、string的这种类似java和python的用法
法1:
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 stack<char>s1; 5 int m1[300]; 6 int cnt=0; 7 char s2[100020]; 8 int main(){ 9 string s; 10 int nn=0; 11 cin>>s; 12 for(int i=0;s[i];i++) m1[s[i]-'a']++; 13 while(!m1[nn]&&nn<26)nn++; 14 for(int i=0;s[i];i++){ 15 if(s1.empty()||m1[nn]){ 16 s1.push(s[i]); 17 m1[s[i]-'a']--; 18 } 19 while(!s1.empty()&&s1.top()<=nn+'a'){//改成小于等于就过了 20 s2[cnt++]=s1.top(),s1.pop(); 21 while(!m1[nn]&&nn<26)nn++; 22 } 23 while(!m1[nn]&&nn<26)nn++; 24 } 25 while(!s1.empty()) s2[cnt++]=s1.top(),s1.pop(); 26 printf("%s\n",s2); 27 }
法二:
1 #include<bits/stdc++.h> 2 #define inf 0x3f3f3f3f 3 using namespace std; 4 typedef long long ll; 5 stack<char>ss; 6 char tmp[100010],x; 7 int main(){ 8 string s; 9 cin>>s; 10 x='z'+5; 11 for(int i=s.size()-1;i>=0;i--) x=min(x,s[i]),tmp[i]=x;//tmp[i]代表该位置能使结果到达最小的值 12 string ans=""; 13 for(int i=0;i<s.size();i++){ 14 while(!ss.empty()&&ss.top()<=tmp[i]) ans+=ss.top(),ss.pop(); 15 ss.push(s[i]); 16 } 17 while(!ss.empty()) ans+=ss.top(),ss.pop(); 18 cout<<ans<<"\n"; 19 return 0; 20 }