Codeforces Round #285 (Div.1 B & Div.2 D) Misha and Permutations Summation --二分+树状数组
题意:给出两个排列,求出每个排列在全排列的排行,相加,模上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 --二分+树状数组的更多相关文章
- 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 ...
- codeforces 1269E K Integers (二分+树状数组)
链接:https://codeforces.com/contest/1269/problem/E 题意:给一个序列P1,P2,P3,P4....Pi,每次可以交换两个相邻的元素,执行最小次数的交换移动 ...
- 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 ...
- 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 ...
- 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 ...
- BestCoder Round #90 //div all 大混战 一题滚粗 阶梯博弈,树状数组,高斯消元
BestCoder Round #90 本次至少暴露出三个知识点爆炸.... A. zz题 按题意copy Init函数 然后统计就ok B. 博弈 题 不懂 推了半天的SG..... 结果这 ...
- Codeforces 1093E Intersection of Permutations (CDQ分治+树状数组)
题意:给你两个数组a和b,a,b都是一个n的全排列:有两种操作:一种是询问区间在数组a的区间[l1,r1]和数组b的区间[l2,r2]出现了多少相同的数字,另一种是交换数组b中x位置和y位置的数字. ...
- 图论/位运算 Codeforces Round #285 (Div. 2) C. Misha and Forest
题目传送门 /* 题意:给出无向无环图,每一个点的度数和相邻点的异或和(a^b^c^....) 图论/位运算:其实这题很简单.类似拓扑排序,先把度数为1的先入对,每一次少一个度数 关键在于更新异或和, ...
- 字符串处理 Codeforces Round #285 (Div. 2) B. Misha and Changing Handles
题目传送门 /* 题意:给出一系列名字变化,问最后初始的名字变成了什么 字符串处理:每一次输入到之前的找相印的名字,若没有,则是初始的,pos[m] 数组记录初始位置 在每一次更新时都把初始pos加上 ...
随机推荐
- MySQL之浅谈MySQL的存储引擎
什么是MySql数据库 通常意义上,数据库也就是数据的集合,具体到计算机上数据库可以是存储器上一些文件的集合或者一些内存数据的集合. 我们通常说的MySql数据库,sql server数据库等 ...
- css中white-space的值pre-wrap
CSS中white-space属性设置如何处理元素内的空白.默认值normal表示:空白会被浏览器忽略. white-space这个属性声明建立布局过程中如何处理元素中的空白符.值 pre-wrap ...
- jquery easyui tabs单击刷新右键刷新
单击刷新 $(".tabs-inner").click(function(){var currTab = self.parent.$('#tabs').tabs('getSelec ...
- 《javascript权威指南》读书笔记(连载)
这是一篇很长的博客 终于把权威指南给买回来了,之前一直犹豫,第一:书太厚,怕买了不能坚持看完.第二:觉得太贵,最少100¥.现在实习也能发点工资了,给自己定了一个志愿:把一个月的工资用于买书.这么一想 ...
- swift学习笔记之-扩展(Extensions)
//扩展(Extensions) import UIKit /*扩展(Extensions):扩展 就是为一个已有的类.结构体.枚举类型或者协议类型添加新功能.这包括在没有权限获取原始源代码的情况下扩 ...
- css引入方式优先级以及不同选择器的优先级区别
我们都知道css有3种基本设置方式即 1.行内也叫嵌入式 例如: <div style='background:red'></div> 2.内联式,在html文件中用style ...
- 轻松玩转jquery。
一.简介 jQuery创始人是美国John Resig,是优秀的Javascript框架: jQuery是一个轻量级.快速简洁的javaScript库.源码戳这 jQuery产生的对象时jQuery独 ...
- 深入理解javascript---命名函数表达式
简单的说,命名函数表达式只有一个用户,那就是在Debug或者Profiler分析的时候来描述函数的名称,也可以使用函数名实现递归,但很快你就会发现其实是不切实际的.当然,如果你不关注调试,那就没什么可 ...
- Javascript数组算法和技巧总结
Js-arrayMethod https://github.com/HerbertKarajan/Js-arrayMethod List unique an array 数组去重 random str ...
- SharePoint 2013 为用户组自定义EventReceiver
前 言 在SharePoint的开发中,EventReceiver是很重要的一个部分,但是,常常遇到有些需要事件的时候,却没有相应的模板,因为EventReceiver创建时的模板只有那几个,除此之外 ...