题目:最不上升也不下降序列
思路:
首先,这实际上是一个数学问题。
对于有n个数排列的数列a,我们可以先将其按 / 上升序列或是下降序列其中一种 / 将其来分开看。
例如,对于数列(1,4,3,2,7,6,5),如果选择下降序列,可以看成这样
(【1】,【4,3,2】,【7,6,5】)
我们将其划分为三个下降子序列。
其LIS和LDS之和的最小值为【所有下降子序列中,最长下降子序列的元素个数(LDS)】+【划分出的下降子序列总数(LIS)】
所以求LIS和LDS之和的最小值就是求【划分子序列总数】与【划分出子序列中最长序列元素数】之和的最小值
那么接下来就要找【划分子序列总数】与【划分出子序列中最长序列元素数】二者之间的关系
由于我们只知道数列a的元素个数n与二者都有关,所以要依据a来建立关系
【划分子序列总数】:单个子序列含有元素个数越多,划分子序列总数越少
【划分出子序列中最长序列元素数】:除最长序列外,其余序列含有的元素个数越多,最长子序列元素数越少
所以我们需要找出最长子序列的元素数,再尽可能让其余子序列含有的元素个数接近或等于最大个数
设n=a*b+c (a>=b,c=a%b) //a为最长下降子序列元素个数,b为元素数量为a的子序列个数,如果c不为0,则还需要再增加一个子序列
则最小和为(a+b),如果c不为0则需再加上1
易证:对于y=xx,(x+t)(x-t)<=x*x(当且仅当t=0时取等)
因此,(a+b)之和固定时,若要使子序列在数量最少的情况下尽可能占有最多的元素,则需使【a=b】(因为a,b为整数,则需在附近取整)
代码(C):#include<stdio.h> int main() {
int n;
scanf("%d",&n);//输入n
int x=1;//x用来记录x*x小于等于n的最大数
while(x*x<n)
{
x++;
}
if(n==x*x)
{
int l=x;//l为输出序列时的数字
printf("%d",l);
l--;
for(int i=2;i<=x;i++)
{
printf(" %d",l);
l--;
}
l+=2*x;
while(l<=n)
{
for(int i=1;i<=x;i++)
{
printf(" %d",l);
l--;
}
l+=2*x;
}
}
else
{
x--;
int y=x;
while(x*y<n)
{
y++;
}
y--;//保证 x*y<n
int re=n-x*y,s=re;//re为remainer余数的缩写 ,不过当x*(y+1)=n时,re=x;
//s为输出序列时的数字
printf("%d",s);
s--;
for(int i=2;i<=re;i++)
{
printf(" %d",s);
s--;
}
s=re+x;
while(s<=n)
{
for(int i=1;i<=x;i++)
{
printf(" %d",s);
s--;
}
s+=2*x;
}
}
return 0;
}

京公网安备 11010502036488号