Codeforces 847B Preparing for Merge Sort

来源:互联网 发布:免费网络推广渠道 编辑:程序博客网 时间:2024/06/05 02:36

题目链接

题目大意:

给出一种n个不同数字的全排列,把他分割成多段严格递增的子序列,并输出分割后的序列.

例如1 4 2 3 5 6

按照递增 分为 1 2 3 5 6和4

题目分析:因为n有2*1e5那么大,所以暴力n^2明显不行了,不过可以在暴力的基础上通过二分查找使时间复杂度降为nlogn.

暴力方法,建立一个vector的数组ans[].里面存放不同段的子序列

从第一个元素开始扫起(设为a),该元素与ans[]中最后的元素(设为last)比较,a>last时说明递增,把a放到该段的后面即ans[i].push_back(a);

当a比所有的last都小时,建立一个新的段,并把a放到该段后面.

很明显上述方法最坏情况会o(n/2)^2爆炸.

优化的话,我们可以设一个新的数组last[],里面存放的事ans[]的末尾元素,这样在查找的时候我们可以用二分法加速.达到nlogn.

#include<iostream>#include<string>#include<cstring>#include<vector>#include<map>#include<algorithm>#include<queue>#include<set>#include<cstdio>#include<functional>#include<iomanip>#include<cmath>#include<stack>#define inf 1<<30#define mod 1030#define esp 1e-8using namespace std;typedef long long LL;const int maxn = (int)(2 * 1e5) + 10;vector<int>ans[maxn];int num[maxn], last[maxn];bool vis[maxn];void init(int n) {for (int i = 0; i <= n; i++) {ans[i].clear();vis[i] = 0;last[i] = 0;}}int find(int size, int key){int first = 0, middle;int half, len;len = size;while (len > 0) {half = len >> 1;middle = first + half;if (last[middle] >= key) {//因为我存last时是倒序,所以分段方法要反过来first = middle + 1;len = len - half - 1;}elselen = half;}return first;}int main() {int n;while (scanf("%d", &n) == 1) {init(n);for (int i = 0; i < n; i++) scanf("%d", &num[i]);int cnt = 0;for (int i = 0; i < n; i++) {bool flag = false;if (i == 0) {ans[cnt].push_back(num[i]);last[cnt++] = num[i];continue;}int t = find(cnt, num[i]);if (t == 0) {//num[i]比所有末尾都大ans[0].push_back(num[i]);last[0] = num[i];}else if (t == cnt) {//num[i]比所有末尾都小last[cnt] = num[i];ans[cnt++].push_back(num[i]);}else {last[t] = num[i];ans[t].push_back(num[i]);}}for (int i = 0; i < cnt; i++) {int l = ans[i].size();for (int j = 0; j < l; j++) {printf("%d", ans[i][j]);printf("%c", j == l - 1 ? '\n' : ' ');}}}}



原创粉丝点击