思路+码一共约45分种,最终得分七十分,我知道自己错在哪,好像不怎么能改得了,但混混分应该还行,先占个坑写写思路吧。
首先我的思路基础,一是冒泡排序进行一次交换代表消去一个逆序对。输入的v代表要消去的逆序对的个数。
二是由于贪心思想,我们优先选取字典序低的字母。
三是我看用例猜测,bbaa、ccbbaa,这种连续两个的应该是要尽量多【当然看了下别人好像三个也行,猜测光荣阵亡。但这点可以看看能不能完善】
在以上的思路基础下,
于是认为,结果字符串应该是类似于那样的结构,再加上fghj这种之后的字母排成的前缀。
例如输入为100时的字符串
jihgfeeddccbbaa
观察字符串,可得所需逆序对数量v=前缀逆序对数+后缀逆序对数+后缀字母数量*前缀字母数量。
其中前缀指的是前面的乱七八糟部分,后缀指的是成对出现的数字。
而由于这样的字符串其实由后缀决定,所以我选择枚举后缀所拥有的字母种类数,最终取得最小值。
所以我们首先任务就是以字母种数创造后缀字符串数组,记录每种字母种类数的值。【仔细想,这里似乎不需要创建数组,之后实时算不知道行不行?】
对于后缀的字符串,我选用了抽象的定义和创造方法。
以”aa“、”bbaa“这种为一个doubleNode,包含它内部的逆序对数和它所拥有的字母数。并且doubleNode数列内部满足递推公式。
这里其实可以根据n的数据范围优化array的大小。这地方还没写。
typedef struct doubleNode{
int eleNum;
int value;
}doubleNode;
doubleNode* CountArray(int n){
doubleNode* array=(doubleNode*)malloc(sizeof(doubleNode)*50);
array[0].eleNum=2;
array[0].value=0;
for(int i=1;i<50;i++){
array[i].value=array[i-1].value+array[i-1].eleNum*2;
array[i].eleNum=array[i-1].eleNum+2;
}
return array;
}
接下来我们再写一个函数,表示前缀字母位数为n时逆序对最多有多少
int CountNixu(int n){
return (n*(n-1))/2;
}
接下来是主体函数【因为是自用,所以变量名取得乱了】。在主体函数中,我们需要枚举后缀每个字母种数,并通过公式计算。以minAlpha变量表示字母数,index表示选到的后缀数组下标,moreNum表示选到的前缀字母个数。
再然后,根据上述三个变量信息组合字符串,return。
这个过程有什么问题呢?我默认了每个前缀字符串都取到了它最大的逆序对数。这一点实际上应该不大可能。针对此,我还真不知道要咋办。我的想法是,除了记录moreNum外,还要记录对应所需的逆序对数,再写一个根据逆序对数计算出字符串排列的函数。我之后有机会试试看。
char* ReturnGoal(int v){
doubleNode* array=CountArray(v);
int minAlpha=INF;
int index=0;
int moreNum=0;
for(int i=0;i<50;i++){
if(array[i].value>v) break;
int left=v-array[i].value;
for(int j=0;j<50;j++){
int sum=array[i].eleNum*j+CountNixu(j);
if(sum>=left){
int eleSum=array[i].eleNum+j;
if(eleSum<=minAlpha){
minAlpha=eleSum;
index=i;
moreNum=j;
}
break;
}
}
}
char* result=(char*)malloc(sizeof(char)*50);
int count=0;
for(int i=index+moreNum;i>index;i--){
result[count++]=(char)(i+'a');
}
for(int i=index;i>=0;i--){
result[count++]=(char)(i+'a');
result[count++]=(char)(i+'a');
//TODO
}
result[count]='\0';
return result;
}
因而算是bug众多。但是毕竟是我为数不多思考比较多的题目www,所以就放在这里了。早睡,保命要紧。
完整代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#define INF 100000
typedef struct doubleNode{
int eleNum;
int value;
}doubleNode;
doubleNode* CountArray(int n){
doubleNode* array=(doubleNode*)malloc(sizeof(doubleNode)*50);
array[0].eleNum=2;
array[0].value=0;
for(int i=1;i<50;i++){
array[i].value=array[i-1].value+array[i-1].eleNum*2;
array[i].eleNum=array[i-1].eleNum+2;
}
return array;
}
//计算逆序数为n的最少位数
int CountNixu(int n){
return (n*(n-1))/2;
}
char* ReturnGoal(int v){
doubleNode* array=CountArray(v);
int minAlpha=INF;
int index=0;
int moreNum=0;
for(int i=0;i<50;i++){
if(array[i].value>v) break;
int left=v-array[i].value;
for(int j=0;j<50;j++){
int sum=array[i].eleNum*j+CountNixu(j);
if(sum>=left){
int eleSum=array[i].eleNum+j;
if(eleSum<=minAlpha){
minAlpha=eleSum;
index=i;
moreNum=j;
}
break;
}
}
}
char* result=(char*)malloc(sizeof(char)*50);
int count=0;
for(int i=index+moreNum;i>index;i--){
result[count++]=(char)(i+'a');
}
for(int i=index;i>=0;i--){
result[count++]=(char)(i+'a');
result[count++]=(char)(i+'a');
//TODO
}
result[count]='\0';
return result;
}
int main(){
printf("%s",ReturnGoal(100));
}