当前位置: 代码迷 >> 综合 >> POJ 2085 treap O(nlogn) 与 贪心 O(n)算法
  详细解决方案

POJ 2085 treap O(nlogn) 与 贪心 O(n)算法

热度:82   发布时间:2023-12-21 00:03:05.0
/* 问题是找出逆序数为m的最小n全排列* 直接暴过去找出第i轮需要第k小数,k = m-(n-1)*(n-2)/2+1 ,当然如果m比较小就k=1了 * 然后用treap找第k小数就可以了。。* O(nlogn)* 听说有O(n)的规律。。其实我做这题主要为了找规律。。。结果就这么被我水了过去。。* 好吧继续找规律*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std;int result[50001], r;
#define MX 100000int size, root;
long long n, m;struct Node
{int l, r, key, rand_fix;int countl, countr;
}node[MX];
//left  rotate
void l_rot(int &index)
{int y = node[index].r;node[index].r = node[y].l;node[index].countr = node[y].countl;node[y].l = index;node[y].countl = node[index].countl + node[index].countr + 1;index = y;
}
//right rotate
void r_rot(int &index)
{int y = node[index].l;node[index].l = node[y].r;node[index].countl = node[y].countr;node[y].r = index;node[y].countr = node[index].countl + node[index].countr + 1;index = y;
}
void insert(int &index, int nkey)
{if(index == -1){index = ++size;node[index].l = node[index].r = -1;node[index].rand_fix = rand();node[index].key = nkey;node[index].countl = node[index].countr = 0;return ;}if(nkey < node[index].key){node[index].countl++;insert(node[index].l, nkey);if(node[node[index].l].rand_fix > node[index].rand_fix)r_rot(index);}else{node[index].countr++;insert(node[index].r, nkey);if(node[node[index].r].rand_fix > node[index].rand_fix)l_rot(index);}
}bool remove(int &index, int nkey)
{if(index == -1) return false;if(nkey < node[index].key){node[index].countl--;return remove(node[index].l, nkey);}else if(nkey > node[index].key){node[index].countr--;return remove(node[index].r, nkey);}if(node[index].l == -1 && node[index].r == -1)index = -1;else if(node[index].l == -1)index = node[index].r;else if(node[index].r == -1)index = node[index].l;else{if(node[node[index].l].rand_fix < node[node[index].r].rand_fix){l_rot(index);node[index].countl--;remove(node[index].l, nkey);}else{r_rot(index);node[index].countr--;remove(node[index].r, nkey);}}return true;
}
int find_value(int nkey, int index)
{if(node[index].countl + 1 == nkey) return node[index].key;else if(node[index].countl >= nkey) return find_value(nkey, node[index].l);else                              return find_value(nkey-node[index].countl-1,node[index].r);
}
void init()
{size = root = -1;for(int i = 1;i <= n;i++) insert(root,i);
}
int main()
{while(scanf("%lld %lld", &n, &m) && n != -1){init();for(r = 1;r <= n;r++){long long ii;long long sum = (n-r)*(n-r-1) / 2;if(sum >= m) ii = 1; else { ii = m - sum + 1; m -= ii-1; }result[r] = find_value((int)ii, root);remove(root,result[r]);}printf("%d", result[1]);for(int i = 2;i <= n;i++) printf(" %d", result[i]);printf("\n");}
}


//贪心法,如果 搞出的东西一定是先由1递增,再由n递减!当然也可以仅由一部分组成
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std;int main()
{long long n, m;bool f[50001];int result[100001], r;while(scanf("%lld %lld", &n, &m) && n != -1){r = 1; memset(f,true,sizeof(f));for(int i = 1;i <= n;i++){long long nxt = (n-i)*(n-i-1)/2;if(nxt > m)result[r++] = i;else{result[r++] = (m-nxt)+i;f[result[r-1]] = false;break;}}int rr = r-2;if(rr<1) rr = 1;for(int i = n;i >= rr;i--){if(f[i]) result[r++] = i;}printf("%d", result[1]);for(int i = 2;i <= n;i++) printf(" %d",result[i]);printf("\n");}}




  相关解决方案