hdu 4377 Sub Sequence

题意:将1到N个数全排列,找出最长上升子序列和最长下降子序列中的较小值,并按字典序输出这个排列。

思路:其实这题真没什么具体方法,如果你的逻辑思维能力较好的话,可以很轻松想出来,不过我是看了题解才明白的,如果N是一个平方数,例如9, 1 , 2 , 3 , 4 , 5 , 6 , 7 ,8 , 9 

它的答案是:3 ,2 , 1 , 6 , 5 , 4,9 , 8 ,7 ,即将序列分成sqrt(n) 段,然后每段都倒序,这样最小的值就是3 ,如果不是平方数,可以分两种情况,m = ceil(sqrt(n)) ;一种是(m-1)*m <n ,一种是 (m-1)*m >= n 。呃,怎么解释这两种情况好呢,第一种情况就是,n%m后剩下的开头的那几个数字在加上在以后的每组里去一个数构成的上升子序列不会大于m,所以不用倒序,第二种情况就是大于了m 所以要把剩下的几个数字也要倒序处理一下。

代码:

View Code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <math.h>
#include <queue>
#define  N 100004
using namespace std ;

int data[N] ;

int main()
{
    int cas , i , m , s , t , n ;

    scanf ( "%d" , &cas );
    while ( cas-- )
    {
        scanf ( "%d" , &n );
        int num = 0 ;
        s = 0 ;
        m = ceil ( sqrt ( 1.0 * n ));
        //判断开头是否要倒序
        if ( m * ( m - 1 ) >= n )
        {
            data[num++] = 1 ;
            s = 1 ;
        }
        //处理开头的数字
        t = ( n - 1 ) % m + 1 ;
        for ( i = t ; i > s ; i-- )
        data[num++] = i ;
        
        //将分成的每组数字倒序
        while ( t + m <= n )
        {
            s = t ;
            t += m ;
            for ( i = t ; i > s ; i-- )
            {
                data[num++] = i ;
            }
        }

        for ( i = 0 ; i < num ; i++ )
        {
            if ( !i )
            printf ( "%d" , data[i] );
            else
            printf ( " %d" , data[i] );
        }
        printf ( "\n" );
    }
    return 0 ;
}
原文地址:https://www.cnblogs.com/misty1/p/2644243.html