<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"><span style="white-space:pre"> </span>题目地址 http://codeforces.com/contest/504/problem/B </span>
这道题目让我更深入的了解了康拓展开。以前只是在做8数码的时候接触了康拓展开了。在比赛的时候想到了康拓展开,但是不知道怎么逆展开,所以没做出来。先介绍一下康拓展开。
康拓展开:
把一个排列展开成如下形式:
其中,a为整数,并且0<=a[i]<i(1<=i<=n) 。其实就是表示的比这个排列要小的排列有多少个。
正好是题目的要求。但是由于数据很大,我们不能用一个数来表示,所以我们先求出康拓展开的数组q[i]和p[i],然后相加的R[i]。重点在后面,怎么取模。这里有一个很重要的结论 .a[i]<i-1。至于为什么,自己想想。那么我们可以想高精度那样向前取模了。取模完成以后就是一个逆展开。逆展开其实就是找到没用用过的数字里面的第R[i]+1的数。可以用2分+树状数组 或者直接平衡树来解决。
解法一 :康拓展开+2分+树状数组
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<queue>
#include<stack>
#include<string>
#include<cstring>
#include<map>
#include<vector>
#include<set>
#include<ctime>
#include<stdlib.h>
using namespace std;
const int mod=99999997;
const int mmax=200010;
const double eps=1e-8;
const double pi=acos(-1.0);
const int inf=0x3fffffff;
#define debug
#define mmax 200010
typedef __int64 LL;
int n;
int p[mmax],q[mmax],R[mmax],c[mmax];
bool use[mmax];
int low_bit(int x)
{
return x&(-x);
}
void updata(int pos)
{
for(int i=pos;i<=n;i+=low_bit(i))
c[i]++;
}
int get_sum(int pos)
{
int ans=0;
for(int i=pos;i>0;i-=low_bit(i))
ans+=c[i];
return ans;
}
int main()
{
while(cin>>n)
{
for(int i=1;i<=n;i++)
scanf("%d",&p[i]),p[i]++;
for(int i=1;i<=n;i++)
scanf("%d",&q[i]),q[i]++;
memset(c,0,sizeof c);
for(int i=1;i<=n;i++)
{
updata(q[i]);
q[i]=q[i]-1-get_sum(q[i]-1);
}
memset(c,0,sizeof c);
for(int i=1;i<=n;i++)
{
updata(p[i]);
p[i]=p[i]-1-get_sum(p[i]-1);
}
for(int i=1;i<=n;i++)
R[i]=q[i]+p[i];
for(int i=n;i>=1;i--)
{
R[i-1]+=R[i]/(n-i+1);
R[i]%=(n-i+1);
}
memset(c,0,sizeof c);
memset(use,0,sizeof use);
for(int i=1;i<=n;i++)
{
int l=R[i]+1,r=n,mid;
while(l<r)
{
mid=(l+r)>>1;
if(mid-1-get_sum(mid-1)-R[i]==0&&(!use[mid]))
break;
if(mid-1-get_sum(mid-1)-R[i]>0)
r=mid;
else
l=mid+1;
}
mid=(l+r)>>1;
R[i]=mid;
use[R[i]]=1;
updata(R[i]);
}
for(int i=1;i<=n;i++)
{
printf("%d%c",R[i]-1,i==n?'\n':' ');
}
}
return 0;
}
解法2 康拓展开+平衡树#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<queue>
#include<stack>
#include<string>
#include<cstring>
#include<map>
#include<vector>
#include<set>
#include<ctime>
#include<stdlib.h>
using namespace std;
const int mod=99999997;
const int mmax=200010;
const double eps=1e-8;
const double pi=acos(-1.0);
const int inf=0x3fffffff;
#define debug
#define mmax 200010
typedef __int64 LL;
int n;
int p[mmax],q[mmax],R[mmax],c[mmax];
bool use[mmax];
int low_bit(int x)
{
return x&(-x);
}
void updata(int pos)
{
for(int i=pos;i<=n;i+=low_bit(i))
c[i]++;
}
int get_sum(int pos)
{
int ans=0;
for(int i=pos;i>0;i-=low_bit(i))
ans+=c[i];
return ans;
}
struct Treap
{
int key,s,r;
Treap * ch[2];
Treap(int key0)
{
key=key0;
s=1;
r=rand();
ch[0]=ch[1]=0;
}
void up()
{
s=1;
s+=(ch[0]?ch[0]->s:0);
s+=(ch[1]?ch[1]->s:0);
}
};
typedef Treap * S_Treap ;
S_Treap root;
void T_clear(S_Treap &p)
{
if(!p)
return ;
T_clear(p->ch[0]);
T_clear(p->ch[1]);
delete p,p=0;
}
void T_rotate(S_Treap &fa,int d)//d=0左旋 ,d=1右旋
{
S_Treap son=fa->ch[d^1];
fa->ch[d^1]=son->ch[d];
son->ch[d]=fa;
fa->up();
son->up();
fa=son;
}
void T_insert(S_Treap &p,int key)
{
if(!p)
{
p=new Treap(key);
return ;
}
if(p->key==key)
return ;
int d=p->key<key;
T_insert(p->ch[d],key);
if(p->r<p->ch[d]->r)
T_rotate(p,d^1);
p->up();
}
int T_kth(int k,S_Treap root)
{
if(!root||!(k>=1&&k<=root->s))
return -1;
S_Treap p=root;
while(1)
{
int num=p->ch[0]?p->ch[0]->s:0;
if(num+1==k)
return p->key;
else if(num+1>k)
p=p->ch[0];
else
{
p=p->ch[1];
k-=num+1;
}
}
}
void f_delete(S_Treap &p,int &key)
{
if(key == p->key)
{
if(p->ch[0] && p->ch[1])
{
bool d = (p->ch[0]->r > p->ch[1]->r);
T_rotate(p, d);
f_delete(p->ch[d], key);
}
else
{
S_Treap del=p;
p = p->ch[p->ch[0] ? 0:1];
delete del,del=0;
}
}
else
f_delete(p->ch[p->key < key], key);
if(p)
p->up();
}
int main()
{
while(cin>>n)
{
for(int i=1;i<=n;i++)
scanf("%d",&p[i]),p[i]++;
for(int i=1;i<=n;i++)
scanf("%d",&q[i]),q[i]++;
memset(c,0,sizeof c);
for(int i=1;i<=n;i++)
{
updata(q[i]);
q[i]=q[i]-1-get_sum(q[i]-1);
}
memset(c,0,sizeof c);
for(int i=1;i<=n;i++)
{
updata(p[i]);
p[i]=p[i]-1-get_sum(p[i]-1);
}
for(int i=1;i<=n;i++)
R[i]=q[i]+p[i];
for(int i=n;i>=1;i--)
{
R[i-1]+=R[i]/(n-i+1);
R[i]%=(n-i+1);
}
T_clear(root);
for(int i=1;i<=n;i++)
T_insert(root,i);
for(int i=1;i<=n;i++)
{
R[i]=T_kth(R[i]+1,root);
f_delete(root,R[i]);
}
for(int i=1;i<=n;i++)
{
printf("%d%c",R[i]-1,i==n?'\n':' ');
}
}
return 0;
}