- 题目链接 :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) {
continue;
}
cout<<i-j+1<<" ";
}
}
cout<<endl;
}
int main()
{
init();
return 0;
}
- 遇到的问题 :分成区间后,代码构造不出来。(博主小白,所以菜到需要想一会)。只要清楚每个区间内部是递增,即j从大到小,区间之间递减,即i每次间隔m。就容易写出两个循环。并且看样例的构造,也可以想出来。