NC220716. 这又是一道难题
描述
小蓝最近学习了一些排序算法,其中冒泡排序让他印象深刻。
在冒泡排序中,每次只能交换相邻的两个元素。
小蓝发现,如果对一个字符串中的字符排序,只允许交换相邻的两个字符,则在所有可能的排序方案中,冒泡排序的总交换次数是最少的。
例如,对于字符串lan 排序,只需要1
次交换。对于字符串qiao 排序,总共需要4
次交换。
小蓝的幸运数字是V
,他想找到一个只包含小写英文字母的字符串,对这个串中的字符进行冒泡排序,正好需要V
次交换。请帮助小蓝找一个这样的字符串。如果可能找到多个,请告诉小蓝最短的那个。如果最短的仍然有多个,请告诉小蓝字典序最小的那个。请注意字符串中可以包含相同的字符。
输入描述
输入一行包含一个整数V
输出描述
输出一个字符串,为所求的答案。
示例1
输入:
4
输出:
bbaa
Java(javac 1.8) 解法, 执行用时: 351ms, 内存消耗: 13936K, 提交时间: 2021-04-08 15:15:09
import java.util.Scanner; public class Main { static int list[]={ 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0 }; static int[] str=new int[300]; static void reset() { int i=0; while(i<26&&list[i]!=0) { list[i]=0; ++i; } } static int getrnum() { int cnt=0; for(int i=0;str[i]!=0;++i) { for(int j=i;str[j]!=0;++j) { if(str[i]>str[j]) { ++cnt; } } } for(int i=0;str[i]!=0;++i) { for(int j=25;j>=0;--j) { if(str[i]-'a'>j) { cnt+=list[j]; } } } int temp=0; for(int i=0;i<26;++i) { cnt+=temp*list[i]; temp+=list[i]; } return cnt; } static int getinc(int c) { int i=0,cnt=0; while(str[i]!=0) { if(str[i]>(c+'a')) { cnt++; } ++i; } for(i=0;i<26;++i) { if(i!=c) { cnt+=list[i]; } } return cnt; } static void set() {//在后部序列中插入元素,保证逆序数最大 int max=0,temp=0,index=0; for(int i=0;i<26;++i) { list[i]++; if((temp=getinc(i))>max) { index=i; max=temp; } list[i]--; } list[index]++; } static void getMaxStr(int l) { reset(); for(int i=0;str[i]!=0;++i,--l); while(l>0) { set(); --l; } } static void printstr() { String Str=""; int i=0; while(str[i]!=0) { Str+=(char)str[i]; ++i; } for(i=25;i>=0;--i) { for(int j=0;j<list[i];++j) { Str+=(char)(i+'a'); } } System.out.println(Str); } static void getans(int num,int l) { for(int i=0;i<l;++i) { for(int j=0;j<26;++j) { str[i]=j+'a'; getMaxStr(l); if(getrnum()>=num) { break; } } } } public static void main(String[] args){ int num; Scanner sc = new Scanner(System.in); num=sc.nextInt(); sc.close(); int l=0; while(getrnum()<num) { ++l; getMaxStr(l); } getans(num,l); printstr(); } }