hihoCoder挑战赛34 B题(快速求第k轮冒泡排序的结果)
官方题解:https://media.hihocoder.com/contests/challenge34/tutorials-previewed.pdf
题目链接:http://hihocoder.com/problemset/problem/1781
题意问对于给定序列A,是否存在一个整数k, 使得A冒泡k轮后变成序列B.
这题一种做法是像官方题解一样写个计算区间最值的数据结构。
而我是另一种做法,通过的逆序数 来判断A怎样能变化到B。
例子
首先我举一个例子:
对于序列 A
8 7 5 1 9 2 6 4 3
其每个位置的逆序数是:
0 1 2 3 0 4 3 5 6 (*)
接着对A冒泡一轮,得到:
7 5 1 8 2 6 4 3 9
这时每个位置的逆序数是:
0 1 2 0 3 2 4 5 0 (**)
那么序列(*)和序列(**) 直接有啥联系呢?
(**)=(*)每个数减-1,并向左平移一格 ,且最多减到0.
证明
现在来证明,每冒泡一轮 所有位置的逆序数-1,并向左移一格。
引理1:对于每轮冒泡排序,若一个位置的前面存在比他大的数, 则他一定会他前面的某个比他大的数进行有且仅有一次交换
这个引理大家自已脑补一下,应该很容易理解是对的。
引理2:若一个位置的前面存在比他大的数,则个位置的逆序数大于0
这个废话,我就不解释了。
证:因为任意一个逆序大于1位置,都与比他大的数交换一次,交换后首先逆序数必然减一,其次,交换后为位置肯定前移1格。 故结论成立。
解题思路
有了这个规律,显然我可以直接O(n)求出任意一轮A的逆序数 与B比较。
再利用【逆序数和】每轮的都会递减的单调性。就可以用二分比较逆序数和的方式,在O(n logn)时间定位b.
或者做一个O(n)预处理,算出n-1轮中,每轮的逆序数和,这样可以把查询的时间复杂度降低至O(n)
当然因为还要对数据进行O(n logn)离散化和求逆序数的原因,所以无论你写哪种最终复杂度都是O(n logn)。
#include<stdio.h>
#include<vector>
#include<algorithm>
#include<string.h>
#include<stack>
#include<math.h>
using namespace std;
#define lowbit(x) (x&(-x))
int a[],b[];
int s1[],s2[];
int c[];
int N=;
int cot[];
int getsum(int x)
{
int sum=;
while(x)
{
sum+=c[x];
x-=lowbit(x);
}
return sum;
}
void add(int x)
{
while(x<=N)
{
c[x]++;
x+=lowbit(x);
}
}
vector<int>que;
int getid(int x)
{
return lower_bound(que.begin(),que.end(),x)-que.begin()+;
}
void cal(int n,int a[],int ans[])
{
int i;
memset(c,,sizeof(c));
for(i=; i<=n; i++)
{
ans[i]=(i-)-getsum(a[i]);
add(a[i]);
}
}
int main()
{
int i,j,t,n,x,y,k,op,q;
long long m;
// freopen("1.in","r",stdin);
//freopen("2.out","w",stdout);
scanf("%d",&t);
for(int cas=; cas<=t; cas++)
{
scanf("%d",&n);
memset(s1,,sizeof(s1));
memset(cot,,sizeof(cot));
que.clear();
for(i=; i<=n; i++)
{
scanf("%d",&a[i]);
que.push_back(a[i]);
}
for(i=; i<=n; i++)
{
scanf("%d",&b[i]);
que.push_back(b[i]);
}
sort(que.begin(),que.end());
m=unique(que.begin(),que.end())-que.begin();
que.resize(m);
int ans=-;
for(i=; i<=n; i++)
{
a[i]=getid(a[i]);
b[i]=getid(b[i]);
}
cal(n,a,s1);
cal(n,b,s2);
long long sum=;
k=;
for(i=; i<=n; i++)
{
cot[s1[i]]++;
k=max(s1[i],k);
sum+=s2[i];
printf("%d ",s1[i]);
}
m=;
for(i=k+; i>; i--)
{
m=m+cot[i];
sum-=m;
if(sum<=)
{
break;
}
}
if(sum==)
{
i--;
for(j=; j<=n; j++)
{
if(max(s1[j+i]-i,)!=s2[j])
{
break;
}
}
if(j>n)
{
sort(a+,a+n+);
sort(b+,b+n+);
for(j=; j<=n; j++)
{
if(a[j]!=b[j])
{
break;
}
}
if(j>n)
{
ans=i;
}
}
}
printf("Case #%d: %d\n",cas,ans);
}
return ; }
AC代码
hihoCoder挑战赛34 B题(快速求第k轮冒泡排序的结果)的更多相关文章
- hihoCoder挑战赛1 毁灭者问题
题目链接:http://hihocoder.com/problemset/problem/1034 数据结构题,由于每个魔法单位有着不同的回复速度和上限,所以不能根据吸收时间点进行查询和更新.但是如果 ...
- hihoCoder挑战赛23
hihoCoder挑战赛23 A.Emulator 题意 给一张图,有\(N(N \le 300)\)个点, 给出任意两点之间的最短路. 求最多可以去掉多少条边,使得任意两点的最短路长度不变. 思路 ...
- 快速求幂(Quick Exponentiation)
接触ACM没几天,向各路大神求教,听说ACM主要是研究算法,所以便开始了苦逼的算法学习之路.话不多说,RT所示,学习快速求幂. 在头文件<math.h>或是<cmath>中,d ...
- NYOJ--102--次方求模(快速求幂取模)
次方求模 时间限制:1000 ms | 内存限制:65535 KB 难度:3 描述 求a的b次方对c取余的值 输入 第一行输入一个整数n表示测试数据的组数(n<100)每组测试只有一 ...
- poj 2001:Shortest Prefixes(字典树,经典题,求最短唯一前缀)
Shortest Prefixes Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 12731 Accepted: 544 ...
- poj 1004:Financial Management(水题,求平均数)
Financial Management Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 126087 Accepted: ...
- 快速求n的质因子(数论)
快速求n的质因子 如何尽快地求出n的质因子呢?我们这里又涉及两个好的算法了! 第一个:用于每次只能求出一个数的质因子,适用于题目中给的n的个数不是很多,但是n又特别大的 #include<std ...
- 阿里聚安全攻防挑战赛第三题Android PwnMe解题思路
阿里聚安全攻防挑战赛第三题Android PwnMe解题思路 大家在聚安全挑战赛正式赛第三题中,遇到android app 远程控制的题目.我们今天带你一探究竟,如何攻破这道题目. 一.题目 购物应用 ...
- 【GDOI 2011 DAY2 T3】零什么的最讨厌了 (快速求阶乘、中国剩余定理)
问题描述: 林记在做数学习题的时候,经常遇到这种情况:苦思冥想了很久终于把问题解出来,结果发现答案是0,久而久之林记在得到习题答案是0的时候就没有了做出一道难题的成就感.于是林记决定:以后出题,答案一 ...
随机推荐
- RabbitMQ实现中AMQP与MQTT消息收发异同
实现了AMQP与MQTT(至多一次)后,用多个队列以topic exchange的方式用相同交换机监听同一个主题(topic),发现情况存在不同,觉得有点意思,所以记录了下来. 用2个MQTT(分别记 ...
- Pandas库入门
pandas库的series类型
- 04,Python网络爬虫之requests模块(1)
引入 Requests 唯一的一个非转基因的 Python HTTP 库,人类可以安全享用. 警告:非专业使用其他 HTTP 库会导致危险的副作用,包括:安全缺陷症.冗余代码症.重新发明轮子症.啃文档 ...
- [bzoj1552][Cerc2007]robotic sort&&[bzoj3506][Cqoi2014]排序机械臂
非常垃圾的一道平衡树,结果被日了一天.很难受嗷嗷嗷 首先不得不说网上的题解让我这个本来就不熟悉平衡树的彩笔很难受——并不好理解. 还好Sinogi大佬非常的神,一眼就切掉了,而且用更加美妙的解法. 题 ...
- 自定义控件的getChildCount
我真的是一步一步走过来,看过来的代码.不是能力问题,而是他们用的,我没用过,我用的他们不用.然后一句一句的问为什么,然后一句一句的去想为什么. 只有这样,才能慢慢的熟悉,东一榔头西一棒子,不是分模块再 ...
- 强烈推荐android初学者,android进阶者看看这个系列教程
强烈推荐android初学者,android进阶者看看这个系列教程 转载 2015年05月30日 23:05:44 695 为什么要研究Android,是因为它够庞大,它够复杂,他激起了我作为一个程序 ...
- selenium自动化测试浏览器驱动安装(属于转载文章)
1.下载selenium压缩包 http://pypi.python.org/pypi/selenium 下载后压缩在python文件下的lib>site-package文件夹下 2.进入sel ...
- freemaker示例
第一步 创建一个User.java文件 来两个变量 public class User { private String userName; private String us ...
- ZOJ 3544 / HDU 4056 Draw a Mess( 并查集好题 )
方法参见:http://blog.acmol.com/?p=751 从最后一个线段开始倒着处理(因为之后的线段不会被它之前的线段覆盖),把这条线段所覆盖的所有线段编号合并到一个集合里,并以最左边线段编 ...
- [CF932D]Tree
题目大意:两种操作: $1\;u\;w:$把下一个点挂在$u$下,权值为$w$. $2\;u\;w:$询问从$u$开始的序列的最长长度.序列为从$u$开始的祖先序列中的不严格上升序列 题解:可以把一个 ...