【题意】给定n,记Perm(x)是所有0,1,2,...,n-1的排列中第x大的排列,对于一个0,1,2,...,n-1的排列p,记p是所有0,1,2,...,n-1的排列中字典序从小到大的第Ord(p)个排列,现在给定两个0,1,2,...,n-1的排列p和q,求Perm((Ord(p)+Ord(q))%(n!)).

【解题方法1】利用康托展开(参见 康托展开 - ACdreamer - 博客频道 - CSDN.NET),由于这里需要动态查询rank和order,需要使用数据结构维护,先用Treap做了一发。

【代码1】

//
//Created by just_sort 2016/10/22
//Copyright (c) 2016 just_sort.All Rights Reserved
//

#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
using namespace __gnu_pbds;
typedef long long LL;
#define LL long long
#define maxn 200005
class treap //treap是一颗随机的二叉排序树,可以实现插入,删除,询问前驱、后驱、排名等功能,不支持负数。各功能的时间复杂度为O(logn)
{
	struct node //treap的节点定义
	{
		node* ch[2];
		int v, r, s;
		int cmp(int x)
		{
			if (x == v) return -1;
			return(x < v ? 0 : 1);
		}
	};
private:
	node* root; //treap的根
	void updata(node* o)
	{
		if (!o) return;
		o->s = 1;
		if (o->ch[0]) o->s += o->ch[0]->s;
		if (o->ch[1]) o->s += o->ch[1]->s;
	}
	void rateto(node* &o, int d)
	{
		node* k;
		k = o->ch[d ^ 1];
		o->ch[d ^ 1] = k->ch[d];
		k->ch[d] = o;
		updata(o);
		updata(k);
		o = k;
	}
	int left(node* o)
	{
		if (!o) return 0;
		if (o->ch[0]) return o->ch[0]->s;
		else return 0;
	}
	void mymemory(node* &o)
	{
		if (!o) return;
		if (o->ch[0]) mymemory(o->ch[0]);
		if (o->ch[1]) mymemory(o->ch[1]);
		free(o);
		o = 0;
	}
	void add(node* &o, int x)
	{
		if (!o)
		{
			o = new node();
			o->ch[0] = o->ch[1] = 0;
			o->v = x;
			o->r = rand()*rand();
			o->s = 1;
			return;
		}
		int d = o->cmp(x);
		if (d == -1) return;
		else
		{
			add(o->ch[d], x);
			updata(o);
			if (o->r < o->ch[d]->r) rateto(o, d ^ 1);
		}
	}
	void remove(node* &o, int x)
	{
		if (!o) return;
		int d = o->cmp(x);
		if (d == -1)
		{
			if (!(o->ch[0]))
			{
				node *k = o->ch[1];
				free(o);
				o = k;
			}
			else if (!(o->ch[1]))
			{
				node *k = o->ch[0];
				free(o);
				o = k;
			}
			else
			{
				int d2 = o->ch[0]->r > o->ch[1]->r ? 1 : 0;
				rateto(o, d2);
				remove(o->ch[d2], x);
			}
		}
		else remove(o->ch[d], x);
		updata(o);
	}
	bool finded(node* o, int x)
	{
		if (!o) return 0;
		while (o)
		{
			int d = o->cmp(x);
			if (d == -1) return 1;
			else o = o->ch[d];
		}
		return 0;
	}
	int Kth(node* o, int k)
	{
		if (!o) return -1;
		if (k == left(o) + 1) return o->v;
		else
		{
			if (k <= left(o)) return Kth(o->ch[0], k);
			else return Kth(o->ch[1], k - left(o) - 1);
		}
	}
	int Rank(node* o, int x, int n)
	{
		if (!o) return -1;
		int d = o->cmp(x);
		if (d == -1) return n + left(o) + 1;
		if (d == 0) return Rank(o->ch[0], x, n);
		else return Rank(o->ch[1], x, n + left(o) + 1);
	}
	int Suc(node* &o, int x)
	{
		if (!o) return -1;
		int d = o->cmp(x);
		if (d == -1)
		{
			if (o->ch[1]) return Suc(o->ch[1], x);
			else return -1;
		}
		else
		{
			int s = Suc(o->ch[d], x);
			if (s != -1) return s;
			if (s == -1 && o->v > x) return o->v;
			else return -1;
		}
	}
	int Pre(node* &o, int x)
	{
		if (!o) return -1;
		int d = o->cmp(x);
		if (d == -1)
		{
			if (o->ch[0]) return Pre(o->ch[0], x);
			else return -1;
		}
		else
		{
			int s = Pre(o->ch[d], x);
			if (s != -1) return s;
			if (s == -1 && o->v < x) return o->v;
			else return -1;
		}
	}
	//以上为treap的功能实现部分
public:
	int size()//返回该treap的内元素的个数
	{
		if (root) return root->s;
		else return 0;
	}
	void insert(int x)//向treap中插元素x,如果x已经在treap中,则不操作
	{
		add(root, x);
	}
	void erase(int x)//删除treap中元素x,如果没有,则不操作
	{
		remove(root, x);
	}
	bool find(int x)//返回x是否在treap中
	{
		return finded(root, x);
	}
	int kth(int x)//返treap中的排名为x的元素的值,如果x非法,返回-1
	{
		if (x <= 0 || x > size()) return -1;
		return Kth(root, x);
	}
	int rank(int x)//返回x在treap中的排名,如果x不在treap中,返回-1
	{
		return Rank(root, x, 0);
	}
	void clear()//清空treap,释放内存
	{
		mymemory(root);
	}
	int  suc(int x)//返回treap中比x大的第一元素的值(后驱),如果x大于等于treap中的最大值,返回-1
	{
		return Suc(root, x);
	}
	int pre(int x)//返回treap中比x小的第一元素的值(前驱),如果x小于等于treap中的最小值,返回-1
	{
		return Pre(root, x);
	}
	treap()//定义初始化;
	{
		root = 0;
	}
};
int a[maxn],b[maxn];
int p[maxn],q[maxn];
int c[maxn];
int main()
{
    int n;
    scanf("%d",&n);
    treap ta,tb;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        ta.insert(a[i]);
    }
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&b[i]);
        tb.insert(b[i]);
    }
    for(int i=1;i<=n;i++)
    {
        p[i]=ta.rank(a[i])-1;
        ta.erase(a[i]);
    }
    for(int i=1;i<=n;i++)
    {
        q[i]=tb.rank(b[i])-1;
        tb.erase(b[i]);
    }
    memset(c,0,sizeof(c));
    for(int i=n;i>=1;i--)
    {
        c[i]+=q[i]+p[i];
        if(c[i]>=n-i+1)
        {
            c[i]-=n-i+1;
            c[i-1]++;
        }
    }
    treap tc;
    for(int i=0;i<n;i++) tc.insert(i);
    for(int i=1;i<=n;i++)
    {
        int tmp=tc.kth(c[i]+1);
        printf("%d ",tmp);
        tc.erase(tmp);
    }
    printf("\n");
    return 0;
}

【代码2 平衡树换成pbds】参见q神。。。

//
//Created by just_sort 2016/10/22
//Copyright (c) 2016 just_sort.All Rights Reserved
//

#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
using namespace __gnu_pbds;
typedef long long LL;
const int maxn = 200005;

typedef tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update>order_set;
order_set s;
order_set::iterator it;
int n, in[maxn], cantor[3][maxn];

int main()
{
   cin>>n;
   for(int i = 0; i < n; i++) cin>>in[i];
   s.clear();
   for(int i = n - 1; i >= 0; i--)
   {
       cantor[1][n-i-1] = s.order_of_key(in[i]);
       s.insert(in[i]);
   }
   for(int i = 0; i < n; i++) cin>>in[i];
   s.clear();
   for(int i = n - 1; i >= 0; i--)
   {
       cantor[2][n-i-1] = s.order_of_key(in[i]);
       s.insert(in[i]);
   }
   int up = 0;
   for(int i = 0; i < n; i++)
   {
       cantor[0][i] = (cantor[1][i] + cantor[2][i] + up) % (i + 1);
       up = (cantor[1][i] + cantor[2][i] + up) / (i + 1);
   }
   s.clear();
   vector<int>ans;
   for(int i = 0; i < n; i++) s.insert(i);
   for(int i = n - 1; i >= 0; i--)
   {
       it = s.find_by_order(cantor[0][i]);
       ans.push_back(*it);
       s.erase(it);
   }
   for(int i = 0; i < ans.size(); i++)
   {
       cout<<ans[i]<<" ";
   }
}


【代码3】树状数组+2分,复杂度 O(n*logn&logn).