Codeforces 1017 problem C

  • 题目链接 :http://codeforces.com/contest/1017/problem/C
  • 题意 :给定一个数n,构造这样一个数列:
    • 长度为n
    • 其中数字为1-n的整数,并且每个数字只出现一次
    • 它的LIS(最长递增子序列)和LDS(最长递减子序列)的和sum 最小。
  • 思路 :因为考虑到LIS和LDS的和,可以把这1-n个数分成m个区间,其中每个区间之内满足递增,每个区间之间满足递减。而递增的长度为每个区间的元素个数,即n/m,而递减的长度为区间的个数m。
    那么问题就转化成 z = n/m + m最小,其中n已知。所以可以通过数学方法得出 当n/m = m,即m = sqrt(n)时,z最小。如此区间就划分出来了。
  • 代码:
#include "bits/stdc++.h"
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
#define fori(i,l,u) for(int i = l;i < u;i++)
#define forj(j,l,u) for(int j = l;j < u;j++)
#define pb push_back
#define mk make_pair
#define F first
#define S second
typedef long long  ll;
typedef pair<int, int> pi;
typedef pair<string,int> ps;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef vector<pi> vpi;
const int maxn = 1e5 + 5;
int n;
int m;
void init(){
    cin>>n;
    m = sqrt(n);
    for (int i = n; i > 0; i -= m) {    //划分每一个区间
        for (int j = m; j > 0; j--) {   //每个区间递增
            if (i-j+1 <= 0) {           //不一定满足最后一个区间也是 n/m的长度,所以 i-j+1, j从m递减, 结果可能为负数或0.
                continue;
            }
            cout<<i-j+1<<" ";
        }
    }
    cout<<endl;
}
int main()
{
    init();
    return 0;
}
  • 遇到的问题 :分成区间后,代码构造不出来。(博主小白,所以菜到需要想一会)。只要清楚每个区间内部是递增,即j从大到小,区间之间递减,即i每次间隔m。就容易写出两个循环。并且看样例的构造,也可以想出来。

猜你喜欢

转载自blog.csdn.net/qq_39763472/article/details/81841745