也是第十一届校赛的C题,不过他把1e5改成了1e7.
一开始就想到用贪心做。思路是这样的:开一个字符数组ans保存答案。然后从头到尾遍历题目给出的字符串S,如果ans数组中还没有这个字母,那么就把字母加到ans尾部。如果已经有这个字母了,那么就看ans中这个字母a后面的一个字母b,如果a>b,那么就把a去掉,a后面的字母依次向前一位,然后在ans的尾部加入与a一样的那个字母。后来发现,这个思路是错误的,如果是类似 “egaeg” 这样的字符串,那么这种思路明显无法找到答案。
后来,在f_zyj的题解(http://blog.csdn.net/f_zyj/article/details/52355698)的点拨下,用新的思路:开一个字符数组ans保存答案。然后从头到尾遍历题目给出的字符串S,如果ans数组中还没有这个字母,那么就把字母加到ans尾部。如果已经有这个字母(设为a)了,那么继续遍历a后面的字母,发现某个字母c<a而且c和a之间的所有字母都大于a并且在后面的S中还有得替换,那么就把a去掉,a后面的字母依次向前一位,然后在ans的尾部加入与a一样的那个字母。
AC代码:
1 #include <cstdio> 2 #include <cstring> 3 using namespace std; 4 const int maxn=1e7+5; 5 char ch[maxn]; 6 int numch[30]; 7 int vis[30]; 8 char ans[30]; 9 int main(){ 10 int now=1; 11 scanf("%s",ch); 12 13 int len=strlen(ch); 14 15 for(int i=0;i<len;i++) 16 numch[ch[i]-'a']++; 17 18 for(int i=0;i<len;i++){ 19 numch[ch[i]-'a']--; 20 if(vis[ch[i]-'a']==0){ 21 ans[now]=ch[i]; 22 vis[ch[i]-'a']=1; 23 now++; 24 continue; 25 } 26 27 for(int m=1;m<now;m++){ 28 if(ans[m]==ch[i]){ 29 for(int n=m+1;n<now;n++){ 30 if(numch[ans[n]-'a']==0&&ans[n]>ans[m]) break; 31 if(ans[n]<ans[m]){ 32 for(int k=m;k<now-1;k++) 33 ans[k]=ans[k+1]; 34 ans[now-1]=ch[i]; 35 break; 36 } 37 } 38 break; 39 } 40 } 41 } 42 printf("%s ",ans+1); 43 return 0; 44 }
这里还有一个小插曲。一开始我并没有用 “int len=strlen(ch);” 把strlen(ch)的结果记起来,而是用了两次strlen(),结果就超时了。。。以后要把strlen()当作一个for循环来看待,不能小看它的运行时间!