hdu 4377 Sub Sequence

本文介绍了一个关于构造法的问题,目标是找到1至n的一个排列,使该排列的最长上升序列和最长下降序列长度的较大值最小。通过分析完全平方数的情况,给出了一个高效的算法实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目大意:

给你一个n(<=100000),让你找出1~n个数的一个排列,使得该排列的h(n)最小,定义h(n)=max(该排列的最长上升序列的长度,该排列的最长下降序列的长度)。

题解:

这个题首先是打表找规律,直接想的话,对于我来说还是相当困难的。这个题是考察构造法的一个题,且有很多细节需要注意。

官方题解:

应该比较容易能够想到这个答案是 sqrt(N) 级别的,这个结论的证明可以参考吴文虎的那本组合数学 p21 。 
当然这还没有结束,怎么找字典序最小的那个解呢?先看看完全平方数吧,对于 4 ,我们有 2 1 4 3 ,对于 9 ,我们有 3 2 1 6 5 4 9 8 7 。嗯,完全平方数的规律还是好找的,那么 5 呢?不就是加一个数么,1 3 2 5 4 ,如果你觉得这是答案,那你就大错特错了,答案是 1 2 5 4 3 。同样,对于 10 ,答案是 1 2 6 5 4 3 10 9 8 7 。 
于是我们就可以构造程序,每次以 ceil(sqrt(N)) 为一组,尽量把大的数安排到后面的组中,同时要注意,一定要分出 ceil(sqrt(N)) 组,能让较小的 1 2 这样的数能够排在前面。
 
最后,这题并不难,但是做到 1Y 也不容易,这就要克服各种逻辑上的问题,形成良好的思维习惯,对于解题来说也是十分重要的。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
using namespace std;
int n,sec,part,c,x;
int s[111111];
int main()
{
    scanf("%d",&sec);
    for(int z=1;z<=sec;z++)
    {
        scanf("%d",&n);
        x=n;c=ceil(sqrt(n));
        for(part=c;part>=1;part--)
        if(part==2 && x<c*2)//细节部分
        {
            int lim=x;
            for(int i=max(lim-c+1,2);i<=lim;i++)
            {
                s[i]=x;
                x--;
            }
            for(int i=1;i<=max(lim-c,1);i++)
            {
                s[i]=x;
                x--;
            }
            break;
        }
        else
        {
            int lim=x;
            for(int i=lim-c+1;i<=lim;i++)
            {
                s[i]=x;
                x--;
            }
        }
        for(int i=1;i<=n-1;i++)
        printf("%d ",s[i]);
        printf("%d\n",s[n]);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值