您的位置:首页 > 其它

排列(康托展开)

2017-10-22 16:52 183 查看
B 排列

文件名 输入文件 输出文件 时间限制 空间限制 perm.pas/c/cpp perm.in perm.out 1s 128MB

题目描述 小 G 喜欢玩排列。现在他手头有两个 n 的排列。n 的排列是由 0,1,2,…,n−1 这 n 的数字组成的。对于一个排列 p,Order(p) 表示 p 是字典序第 Order(p) 小的 排列(从 0 开始计数)。对于小于 n! 的非负数 x,Perm(x) 表示字典序第 x 小的 排列。 现在,小 G 想求一下他手头两个排列的和。两个排列 p 和 q 的和为 sum = Perm((Order(p) + Order(q))%n!)。

输入格式 输入文件第一行一个数字 n,含义如题。 接下来两行,每行 n 个用空格隔开的数字,表示小 G 手头的两个排列。

输出格式 输出一行 n 个数字,用空格隔开,表示两个排列的和。

样例输入 1

2

0 1

1 0

样例输出 1

1 0

样例输入 2

3

1 2 0

2 1 0

样例输出 2

1 0 2

数据范围 1、2、3、4 测试点,1 ≤ n ≤ 10。 5、6、7 测试点,1 ≤ n ≤ 5000,保证第二个排列的 Order ≤ 1e5。 8、9、10 测试点,1 ≤ n ≤ 5000。

说实话没学过康托展开,但是自己画还是能画出来的,然后用树状数组维护一下,然后维护之后不知道怎么写了,就写了暴力上去,没想到A了

查了一下康托展开X=a
(n-1)!+a[n-1](n-2)!+…+a[i]*(i-1)!+…+a[1]*0! ,其中a[i]为当前未出现的元素中是排在第几个(从0开始)

我用树状数组维护求出了a[i],然后暴力膜(标解似乎是高精度的逆康托展开,然而并不会)

program df;

var i,j,n,m,x,y,z,k,t,l,r:longint;

s1,s2:ansistring;

a,b,c,d,f,g,h,fac:array[0..100000] of longint;

function lowbit(x:longint):longint;

begin

exit(x and -x);

end;

procedure add(x:longint);

var i,j:longint;

begin

i:=x;

while i<=n do

begin

f[i]:=f[i]+1;

i:=i+lowbit(i);

end;

end;

function sum(x:longint):longint;

var i,j:longint;

begin

i:=x; sum:=0;

while i>0 do

begin

sum:=sum+f[i];

i:=i-lowbit(i);

end;

exit(sum);

end;

procedure add2(x:longint);

var i,j:longint;

begin

i:=x;

while i<=n do

begin

g[i]:=g[i]+1;

i:=i+lowbit(i);

end;

end;

function sum2(x:longint):longint;

var i,j:longint;

begin

i:=x; sum2:=0;

while i>0 do

begin

sum2:=sum2+g[i];

i:=i-lowbit(i);

end;

exit(sum2);

end;

begin

assign(input,’perm.in’);

reset(input);

assign(output,’perm.out’);

rewrite(output);

readln(n);

for i:=1 to n do

read(a[i]);

readln;

for i:=1 to n do

read(b[i]);

for i:=1 to n do

begin

a[i]:=a[i]+1;

b[i]:=b[i]+1;

end;

for i:=1 to n do

begin

c[n-i]:=a[i]-1-sum(a[i]);

d[n-i]:=b[i]-1-sum2(b[i]);

add(a[i]);

add2(b[i]);

end;

c[0]:=c[0];

for i:=0 to n-1 do

begin

c[i]:=c[i]+d[i];

c[i+1]:=c[i+1]+(c[i] div (i+1));

c[i]:=c[i] mod (i+1);

end;

for i:=n-1 downto 0 do

begin

k:=0; j:=0;

while (c[i]>k) do

begin

if h[j]=0 then inc(k);

inc(j);

end;

while h[j]=1 do inc(j);

h[j]:=1;

write(j,’ ‘);

end;

close(input);

close(output);

end.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: