codeforces #502 C The Phone Number【数学】

题目链接:http://codeforces.com/contest/1017/problem/C

题意:给出n,输出由1到n排列的数列中最长上升子序列的长度+最长递减子序列长度和的最小的数列,如果有多个,输出其中一个;

思路:假设n是9,那么正确的排列方式是  789 | 456 | 123 ,我们可以看到,用 | 分开的单个区域各自都为一个独立的上升子序列,从左往右看,每一个区域的的上升子序列的最小数字都比左边区域的上升子序列的最大数字都大,用 x来代表最长上升子序列的区域数,y来代表所有区域中,最长上升子序列最长的长度;y自然就是最长上升子序列的长度,而最长递减子序列的长度就是区域的个数,为什么?因为左边区域的每一个数都比右边区域的每一个数大,而单个区域里面的数列是构不成递减子序列的,所以递减子序列的数是从单个区域块中取任意一个数,所以当x+y最小的时候,就是最长上升子序列+最长递减子序列的最小值,x和y要如何取值才能最小?  x + y >= x*y; 下面给出代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>

using namespace std;

#define IOS ios::sync_with_stdio(false); cin.tie(0);

typedef long long ll;

const int Maxn = 2e5+10;
const int INF = 0x3f3f3f3f;

int main (void)
{
    IOS
    int n;
    cin >> n;
    int x = sqrt(n); 
    int tmp = n,m = n/x;
    for (int i = 1; i <= m; ++i) {
            tmp-=x; ;
            for (int j = tmp+1; j <= tmp+x; ++j) cout << j << " ";
    }
    for (int j = 1; j <= tmp; ++j) cout << j << " ";
    cout << endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/godleaf/article/details/81587663