排列(康托展开)
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.
文件名 输入文件 输出文件 时间限制 空间限制 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.
相关文章推荐
- noip2004 火星人 (按照康托展开,从一个排列生成下一个排列)
- 全排列与 康托展开
- 全排列方法二(康托展开)
- 康托展开(方便排列计数)
- 康托展开:对全排列的HASH和还原,判断搜索中的某个排列是否出现过
- 蓝桥 排列序数(康托展开)
- 全排列计算(康托展开)
- 排列序列 (康托展开)
- 2017蓝桥杯官方模拟题 排列序数(康托展开)
- 康托展开(用于全排列与整数的转换)
- 蓝桥模拟题 排列序数(康托展开)
- 全排列散列 - (康托展开 和 逆康托展开)
- 全排列字典序与序号的一一对应关系 康托展开 perm2num num2 perm
- 康托展开(用于全排列与整数的转换)
- (蓝桥杯练习)3.排列序数(康托展开)
- 用于数字康托展开 用于求一个排列的序号或序号对应的排列或对排列的hash
- leetcode[60]Permutation Sequence 以及 全排列的编码与解码——康托展开 (附完整代码)
- HDU 1043 全排列 康托展开
- 全排列的本质——康托展开以及本质原理分析——选取第N个——由序列推知第几个
- 康托展开 全排列