题意:给出两个排列,求出每个排列在全排列的排行,相加,模上n!(全排列个数)得出一个数k,求出排行为k的排列。

解法:首先要得出定位方法,即知道某个排列是第几个排列。比如 (0, 1, 2), (0, 2, 1), (1, 0, 2), (1, 2, 0), (2, 0, 1), (2, 1, 0).

拿排列(1,2,0)来说,首位是1,前面有cnt=1个小于1的没被用过的数(0),所以它的排行要加上(cnt=1)*2!,第二位为2,因为1已经放了,所以小于2的只有0了,即cnt=1个,所以,排行又要加上(cnt=1)*1!,所以排行为3.

推出一般性结论:

pre[i]表示小于 i 且没被占据的数的个数。我们可以用树状数组一边更新一边查询求得给出的两个排列的所有pre[]值,存到p数组:p1[i] = pre1[b1[i]],p2[i] = pre2[b2[i]]

然后Rank和为(p1[i]+p2[i])*(n-1)! + ... + (p1[n]+p2[n])*0! = p3[1]*(n-1)! + ... + p3[n]*0! ,但是得出的表达式可能不是规整的形式,这是我们需要检测一边,从后往前扫,如果p3[i] >= (n-i+1), 说明第 i 项已经超过 (n-i+1)*(n-i), 那么就应进位到(n-i+1)!, 即p3[i-1]+=1,依此类推,第1位的进位不再考虑。

最后得出规整的正确的p3[]序列,然后通过树状数组+二分在nlognlogn的复杂度将p3每位对应到结果排列的每位数上,即为上面求Rank(p)的反操作,不细讲了,想一想就知道了。

代码:

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <cstdlib>
  5. #include <cmath>
  6. #include <algorithm>
  7. #include <string>
  8. #include <vector>
  9. #include <queue>
  10. using namespace std;
  11. #define N 200107
  12.  
  13. int p1[N],p2[N],p3[N],c[N];
  14. int n;
  15.  
  16. int lowbit(int x) { return x&-x; }
  17. void modify(int x,int val)
  18. {
  19. while(x <= n+)
  20. {
  21. c[x] += val;
  22. x += lowbit(x);
  23. }
  24. }
  25. int getsum(int x)
  26. {
  27. int res = ;
  28. while(x > )
  29. {
  30. res += c[x];
  31. x -= lowbit(x);
  32. }
  33. return res;
  34. }
  35.  
  36. int main()
  37. {
  38. int i,j,x;
  39. while(scanf("%d",&n)!=EOF)
  40. {
  41. memset(c,,sizeof(c));
  42. for(i=;i<=n;i++) modify(i,);
  43. for(i=;i<=n;i++)
  44. {
  45. scanf("%d",&x);
  46. x++;
  47. p1[i] = getsum(x-);
  48. modify(x,-);
  49. }
  50. memset(c,,sizeof(c));
  51. for(i=;i<=n;i++) modify(i,);
  52. for(i=;i<=n;i++)
  53. {
  54. scanf("%d",&x);
  55. x++;
  56. p2[i] = getsum(x-);
  57. modify(x,-);
  58. }
  59. memset(p3,,sizeof(p3));
  60. for(i=n;i>=;i--)
  61. {
  62. p3[i] += p1[i]+p2[i];
  63. if(p3[i] >= (n-i+))
  64. {
  65. p3[i] = p3[i]-(n-i+);
  66. if(i != ) p3[i-]++;
  67. }
  68. }
  69. memset(c,,sizeof(c));
  70. for(i=;i<=n;i++) modify(i,);
  71. // for(i=1;i<=n;i++)
  72. // cout<<p3[i]<<" ";
  73. // cout<<endl;
  74. for(i=;i<=n;i++)
  75. {
  76. int low = , high = n;
  77. while(low <= high)
  78. {
  79. int mid = (low+high)/;
  80. if(getsum(mid-) > p3[i])
  81. high = mid-;
  82. else if(getsum(mid-) == p3[i] && getsum(mid)-getsum(mid-) == )
  83. high = mid-;
  84. else if(getsum(mid-) == p3[i] && getsum(mid)-getsum(mid-) < )
  85. low = mid+;
  86. else if(getsum(mid-) < p3[i])
  87. low = mid+;
  88. }
  89. modify(low,-);
  90. printf("%d ",low-);
  91. }
  92. puts("");
  93. }
  94. return ;
  95. }

比赛中写的代码,没有最简化,有很多冗余和多此一举的地方。

Codeforces Round #285 (Div.1 B & Div.2 D) Misha and Permutations Summation --二分+树状数组的更多相关文章

  1. Codeforces Round #423 (Div. 2, rated, based on VK Cup Finals) E. DNA Evolution 树状数组

    E. DNA Evolution 题目连接: http://codeforces.com/contest/828/problem/E Description Everyone knows that D ...

  2. codeforces 1269E K Integers (二分+树状数组)

    链接:https://codeforces.com/contest/1269/problem/E 题意:给一个序列P1,P2,P3,P4....Pi,每次可以交换两个相邻的元素,执行最小次数的交换移动 ...

  3. Codeforces Round #227 (Div. 2) E. George and Cards set内二分+树状数组

    E. George and Cards   George is a cat, so he loves playing very much. Vitaly put n cards in a row in ...

  4. Codeforces Round #424 (Div. 2, rated, based on VK Cup Finals) E. Cards Sorting 树状数组

    E. Cards Sorting time limit per test 1 second memory limit per test 256 megabytes input standard inp ...

  5. Codeforces Round #424 (Div. 2, rated, based on VK Cup Finals) Cards Sorting(树状数组)

    Cards Sorting time limit per test 1 second memory limit per test 256 megabytes input standard input ...

  6. BestCoder Round #90 //div all 大混战 一题滚粗 阶梯博弈,树状数组,高斯消元

    BestCoder Round #90 本次至少暴露出三个知识点爆炸.... A. zz题 按题意copy  Init函数 然后统计就ok B. 博弈 题  不懂  推了半天的SG.....  结果这 ...

  7. Codeforces 1093E Intersection of Permutations (CDQ分治+树状数组)

    题意:给你两个数组a和b,a,b都是一个n的全排列:有两种操作:一种是询问区间在数组a的区间[l1,r1]和数组b的区间[l2,r2]出现了多少相同的数字,另一种是交换数组b中x位置和y位置的数字. ...

  8. 图论/位运算 Codeforces Round #285 (Div. 2) C. Misha and Forest

    题目传送门 /* 题意:给出无向无环图,每一个点的度数和相邻点的异或和(a^b^c^....) 图论/位运算:其实这题很简单.类似拓扑排序,先把度数为1的先入对,每一次少一个度数 关键在于更新异或和, ...

  9. 字符串处理 Codeforces Round #285 (Div. 2) B. Misha and Changing Handles

    题目传送门 /* 题意:给出一系列名字变化,问最后初始的名字变成了什么 字符串处理:每一次输入到之前的找相印的名字,若没有,则是初始的,pos[m] 数组记录初始位置 在每一次更新时都把初始pos加上 ...

随机推荐

  1. php扩展php_curl windows 安装问题

    关于安装php扩展php_curl 出现的提示错误,导致php_curl无法安装 apache 错误日志: PHP Warning: PHP Startup: in Unknown on line 0 ...

  2. asp.net中控制反转的理解

    对IOC的解释为:“Inversion of control is a common characteristic of frameworks, so saying that these lightw ...

  3. 设置css通用字体

    font-family: "Helvetica Neue","Arial","PingFang SC","Hiragino San ...

  4. CSS3滚动条-webkit-scrollbar

    webkit现在支持拥有overflow属性的区域,列表框,下拉菜单,textarea的滚动条自定义样式. 如果你想跳过介绍,直接看demo的话,请点击demo 滚动条是一个伪元素,可以自定义样式.这 ...

  5. 关于JS堆栈与拷贝

    1.栈(stack)和堆(heap) stack为自动分配的内存空间,它由系统自动释放:而heap则是动态分配的内存,大小不定也不会自动释放. 2.基本类型和引用类型 基本类型:存放在栈内存中的简单数 ...

  6. JavaScript中的各种变量提升(Hoisting)

    首先纠正下,文章标题里的 “变量提升” 名词是随大流叫法,“变量提升” 改为 “标识符提升” 更准确.因为变量一般指使用 var 声明的标识符,JS 里使用 function 声明的标识符也存在提升( ...

  7. 把应用push到/system/app上面后,出现java.lang.UnsatisfiedLinkError的问题

    把应用push到/system/app下面后,加载.so库的问题 01-01 00:07:08.186: E/MessageQueue-JNI(2683): java.lang.Unsatisfied ...

  8. 私有Pods封装个推SDK功能(解决方案)

    一:运用场景 公司中同时有好几个APP在开发,而且每个APP都有使用到集成个推SDK来处理消息的功能,以前的做法是每个APP都去集成并在AppDelegate处理一些SDK的代码,包含个推基础配置.消 ...

  9. C语言中的数组的一些笔记

    C语言是面向过程的语言. 计算数组长度: Int count =sizeof(ages)/sizeof(int); C语言里面输出字符串,必须以'\0'结束,如果没有则一直执行下去. Char nam ...

  10. Socket的简单使用

    一.Socket: Socket又称”套接字" 网络上的两个程序通过一个双向的通信链接实现数据的交换,这个连接的一端成为一个socket 应用程序通常通过”套接字”向网络发出请求或者应答网络 ...