当前位置:   article > 正文

codeforces 501D Misha and Permutations Summation(康拓展开+数据结构)_康拓2 电梯数据结构

康拓2 电梯数据结构

题目链接

Misha and Permutations Summation
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Let's define the sum of two permutations p and q of numbers 0, 1, ..., (n - 1) as permutation , where Perm(x) is the x-th lexicographically permutation of numbers 0, 1, ..., (n - 1) (counting from zero), and Ord(p) is the number of permutation p in the lexicographical order.

For example, Perm(0) = (0, 1, ..., n - 2, n - 1)Perm(n! - 1) = (n - 1, n - 2, ..., 1, 0)

Misha has two permutations, p and q. Your task is to find their sum.

Permutation a = (a0, a1, ..., an - 1) is called to be lexicographically smaller than permutation b = (b0, b1, ..., bn - 1), if for some kfollowing conditions hold: a0 = b0, a1 = b1, ..., ak - 1 = bk - 1, ak < bk.

Input

The first line contains an integer n (1 ≤ n ≤ 200 000).

The second line contains n distinct integers from 0 to n - 1, separated by a space, forming permutation p.

The third line contains n distinct integers from 0 to n - 1, separated by spaces, forming permutation q.

Output

Print n distinct integers from 0 to n - 1, forming the sum of the given permutations. Separate the numbers by spaces.

Sample test(s)
input
2
0 1
0 1
output
0 1
input
2
0 1
1 0
output
1 0
input
3
1 2 0
2 1 0
output
1 0 2
Note

Permutations of numbers from 0 to 1 in the lexicographical order: (0, 1), (1, 0).

In the first sample Ord(p) = 0 and Ord(q) = 0, so the answer is .

In the second sample Ord(p) = 0 and Ord(q) = 1, so the answer is .

Permutations of numbers from 0 to 2 in the lexicographical order: (0, 1, 2), (0, 2, 1), (1, 0, 2), (1, 2, 0), (2, 0, 1), (2, 1, 0).

In the third sample Ord(p) = 3 and Ord(q) = 5, so the answer is .


题意:已知两个0到n-1的n个数的排列a,b。ord(a)在0到n-1的数的所有排列中的按字典序排序后的位置。ord(b)同理。输出排列x,ord(x)=(ord(a)+ord(b))%n!。

题解:首先要了解康拓展开:康拓展开

x=a[n]*(n-1)!+a[n-1]*(n-2)!+.......a[1]*0!。,0<=a[i]<i。

由于数据范围太大,直接求出ord显然是不行的。我们可以根据a,b的康拓展开式,直接求出x的康拓展开式。

因为a[i]<=i-1。

所以,排列a康拓展开有可能的最大值为:(n-1)*(n-1)!+(n-2)*(n-2)!+.....(i-1)*(i-1)!+...0*0!

同理排列b康拓展开的最大值为:(n-1)*(n-1)!+(n-2)*(n-2)!+.....(i-1)*(i-1)!+...0*0!

      将两个排列的康拓展开相加可得:n!+(n-1)*(n-1)!+(n-2)*(n-2)!+....(i-1)*(i-1)!+....0*0!

       上式%n!,则可得:(n-1)*(n-1)!+(n-2)*(n-2)!+.........(i-1)*(i-1)!+....0*0!

由此可见,两个排列的康拓展开之和,最大到达n!的数量级,对n!取模过后,剩下的就是一个排列的康拓展开。我们把这个康拓展开逆展开,就解决问题了。

我们可以用类似高精度加法的方法,求出两个排列的康拓展开的和%n!的康拓展开。然后用树状数组+二分的方法,将康拓展开逆展开。复杂度为O(n*lgn*lgn)。当然也可以用平衡树或者线段树,不用二分,复杂度为O(n*lgn)。

我的代码是树状数组+二分的方法,代码如下:

  1. #include<stdio.h>
  2. #include<iostream>
  3. #include<algorithm>
  4. #include<string.h>
  5. #include<string>
  6. #include<queue>
  7. #include<stack>
  8. #include<map>
  9. #include<set>
  10. #include<stdlib.h>
  11. #include<vector>
  12. #define inff 0x3fffffff
  13. #define nn 210000
  14. #define mod 1000000007
  15. typedef long long LL;
  16. const LL inf64=inff*(LL)inff;
  17. using namespace std;
  18. int n;
  19. int a[nn],b[nn];
  20. int ans[nn];
  21. int c[nn];
  22. int dp[nn];
  23. int lowbit(int x)
  24. {
  25. return x&(-x);
  26. }
  27. void modify(int x,int y)
  28. {
  29. for(int i=x;i<=n;i+=lowbit(i))
  30. {
  31. c[i]+=y;
  32. }
  33. }
  34. int getsum(int x)
  35. {
  36. int sum=0;
  37. for(int i=x;i>=1;i-=lowbit(i))
  38. sum+=c[i];
  39. return sum;
  40. }
  41. int main()
  42. {
  43. int i;
  44. while(scanf("%d",&n)!=EOF)
  45. {
  46. for(i=1;i<=n;i++)
  47. {
  48. scanf("%d",&a[i]);
  49. }
  50. for(i=1;i<=n;i++)
  51. {
  52. scanf("%d",&b[i]);
  53. }
  54. int ix;
  55. memset(c,0,sizeof(c));
  56. for(i=1;i<=n;i++)
  57. {
  58. ix=getsum(a[i]);
  59. modify(a[i]+1,1);
  60. a[i]=a[i]-ix;
  61. }
  62. memset(c,0,sizeof(c));
  63. for(i=1;i<=n;i++)
  64. {
  65. ix=getsum(b[i]);
  66. modify(b[i]+1,1);
  67. b[i]=b[i]-ix;
  68. }
  69. ix=0;
  70. for(i=n;i>=1;i--)
  71. {
  72. ans[i]=(a[i]+b[i]+ix)%(n-i+1);
  73. ix=(a[i]+b[i]+ix)/(n-i+1);
  74. }
  75. for(i=1;i<=n+1;i++)
  76. dp[i]=i;
  77. memset(c,1,sizeof(1));
  78. int l,r,mid;
  79. for(i=1;i<=n;i++)
  80. {
  81. l=1,r=n;
  82. while(l<r)
  83. {
  84. mid=(l+r)/2;
  85. if(mid-getsum(mid)<ans[i]+1)
  86. l=mid+1;
  87. else
  88. r=mid;
  89. }
  90. ans[i]=l;
  91. modify(l,1);
  92. }
  93. for(i=1;i<=n;i++)
  94. {
  95. printf("%d%c",ans[i]-1,i==n?'\n':' ');
  96. }
  97. }
  98. return 0;
  99. }

线段树做法代码如下:

  1. #include<algorithm>
  2. #include<iostream>
  3. #include<cstdio>
  4. #include<cstring>
  5. #include<vector>
  6. #include<math.h>
  7. #define nn 210000
  8. #define eps 1e-8
  9. #define inff 0x7fffffff
  10. #define lson rt<<1,l,m
  11. #define rson rt<<1|1,m+1,r
  12. #define mod 20071027
  13. using namespace std;
  14. typedef __int64 LL;
  15. typedef unsigned long long LLU;
  16. int n;
  17. int a[nn],b[nn],c[nn];
  18. int L[nn*4],R[nn*4],sum[nn*4];
  19. void push_up(int id)
  20. {
  21. sum[id]=sum[id<<1]+sum[id<<1|1];
  22. }
  23. void build(int id,int l,int r)
  24. {
  25. L[id]=l,R[id]=r;
  26. if(l==r)
  27. {
  28. sum[id]=1;
  29. return ;
  30. }
  31. int m=(l+r)>>1;
  32. build(2*id,l,m);
  33. build(2*id+1,m+1,r);
  34. push_up(id);
  35. }
  36. void update(int id,int x)
  37. {
  38. if(L[id]==R[id])
  39. {
  40. sum[id]=0;
  41. return ;
  42. }
  43. int m=(L[id]+R[id])>>1;
  44. if(x<=m)
  45. update(2*id,x);
  46. else
  47. update(2*id+1,x);
  48. push_up(id);
  49. }
  50. int query(int id,int l,int r)
  51. {
  52. if(L[id]>=l&&R[id]<=r)
  53. {
  54. return sum[id];
  55. }
  56. int m=(L[id]+R[id])>>1;
  57. int re=0;
  58. if(l<=m)
  59. re+=query(2*id,l,r);
  60. if(r>m)
  61. re+=query(2*id+1,l,r);
  62. return re;
  63. }
  64. int ask(int id,int x)
  65. {
  66. if(L[id]==R[id])
  67. {
  68. sum[id]=0;
  69. return L[id];
  70. }
  71. int re;
  72. if(sum[2*id]>=x)
  73. re=ask(2*id,x);
  74. else
  75. re=ask(2*id+1,x-sum[2*id]);
  76. push_up(id);
  77. return re;
  78. }
  79. int main()
  80. {
  81. int i,x;
  82. while(scanf("%d",&n)!=EOF)
  83. {
  84. build(1,0,n-1);
  85. for(i=1;i<=n;i++)
  86. {
  87. scanf("%d",&x);
  88. update(1,x);
  89. a[i]=query(1,0,x);
  90. }
  91. build(1,0,n-1);
  92. for(i=1;i<=n;i++)
  93. {
  94. scanf("%d",&x);
  95. update(1,x);
  96. b[i]=query(1,0,x);
  97. }
  98. int ix=0;
  99. build(1,0,n-1);
  100. for(i=n;i>=1;i--)
  101. {
  102. c[i]=(a[i]+b[i]+ix)%(n-i+1);
  103. ix=(a[i]+b[i]+ix)/(n-i+1);
  104. }
  105. for(i=1;i<=n;i++)
  106. {
  107. printf("%d%c",ask(1,c[i]+1),i==n?'\n':' ');
  108. }
  109. }
  110. return 0;
  111. }



声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/75468
推荐阅读
相关标签
  

闽ICP备14008679号