题意:给出两个排列,求出每个排列在全排列的排行,相加,模上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)的反操作,不细讲了,想一想就知道了。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
using namespace std;
#define N 200107 int p1[N],p2[N],p3[N],c[N];
int n; int lowbit(int x) { return x&-x; }
void modify(int x,int val)
{
while(x <= n+)
{
c[x] += val;
x += lowbit(x);
}
}
int getsum(int x)
{
int res = ;
while(x > )
{
res += c[x];
x -= lowbit(x);
}
return res;
} int main()
{
int i,j,x;
while(scanf("%d",&n)!=EOF)
{
memset(c,,sizeof(c));
for(i=;i<=n;i++) modify(i,);
for(i=;i<=n;i++)
{
scanf("%d",&x);
x++;
p1[i] = getsum(x-);
modify(x,-);
}
memset(c,,sizeof(c));
for(i=;i<=n;i++) modify(i,);
for(i=;i<=n;i++)
{
scanf("%d",&x);
x++;
p2[i] = getsum(x-);
modify(x,-);
}
memset(p3,,sizeof(p3));
for(i=n;i>=;i--)
{
p3[i] += p1[i]+p2[i];
if(p3[i] >= (n-i+))
{
p3[i] = p3[i]-(n-i+);
if(i != ) p3[i-]++;
}
}
memset(c,,sizeof(c));
for(i=;i<=n;i++) modify(i,);
// for(i=1;i<=n;i++)
// cout<<p3[i]<<" ";
// cout<<endl;
for(i=;i<=n;i++)
{
int low = , high = n;
while(low <= high)
{
int mid = (low+high)/;
if(getsum(mid-) > p3[i])
high = mid-;
else if(getsum(mid-) == p3[i] && getsum(mid)-getsum(mid-) == )
high = mid-;
else if(getsum(mid-) == p3[i] && getsum(mid)-getsum(mid-) < )
low = mid+;
else if(getsum(mid-) < p3[i])
low = mid+;
}
modify(low,-);
printf("%d ",low-);
}
puts("");
}
return ;
}

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

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. OriDomi – 像折叠纸张一样折叠 DOM 元素

    Web 原本是扁平化的,但是现在你可以折起来.OriDomi 是一个开源的 JavaScript 库,使得 DOM 元素能够实现像纸折一样折叠的效果.在创建你所看到的场景背后,OriDomi 做了大量 ...

  2. CSS学习总结(二)

    一.id及class选择符 id和class的名称是由用户自定义的.id号可以唯一地标识html元素,为元素指定样式.id选择符以#来定义. 1.id选择符   注:在网页中,每个id名只能是唯一不重 ...

  3. sap去除后缀0方法

    原贴地址:http://fuhesap.com/SAP/179.html SHIFT str LEFT DELETING LEADING '0'.如果要在layout显示不出前面的0 格式: & ...

  4. 操作系统开发系列—13.g.操作系统的系统调用 ●

    在我们的操作系统中,已经存在的3个进程是运行在ring1上的,它们已经不能任意地使用某些指令,不能访问某些权限更高的内存区域,但如果一项任务需要这些使用指令或者内存区域时,只能通过系统调用来实现,它是 ...

  5. Android开发实战(十八):Android Studio 优秀插件:GsonFormat

    Android Studio 优秀插件系列: Android Studio 优秀插件(一):GsonFormat Android Studio 优秀插件(二): Parcelable Code Gen ...

  6. Android不同屏幕适配

    1.尽量使用线性布局(LinearLayout)和相对布局(RelativeLayout),不要使用绝对布局. 2.尽量使用dip和sp,不要使用px. 3.为不同的分辨率提供不同的布局文件和图片.  ...

  7. 【代码笔记】iOS-给背景图赋值颜色

    代码: - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. // ...

  8. 【代码笔记】iOS-钢琴小游戏

    一,效果图. 二,工程图. 三,代码. RootViewController.h #import <UIKit/UIKit.h> //加入头文件 #import <AudioTool ...

  9. SSH框架搭建详解 及 乱码处理

    http://www.360doc.com/content/15/1031/21/21693298_509739569.shtml struts 除了struts的mvc外,还有拦截器,国际化,str ...

  10. 去掉字符序列左边和右边的空格 trim()

    str = " ai lafu yo ";str = trim(str); 输出的将是"ai lafu yo"