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的时候就没有了做出一道难题的成就感.于是林记决定:以后出题,答案一 ...
随机推荐
- IAR 编译时找不到头文件的解决方法
Fatal Error[Pe1696]: cannot open source file "x.h" 那是因为头文件路径没有找对 到报错的.c源文件 选中右键 选择options ...
- C# 窗口关闭事件
首先添加一个退出事件函数 //退出按键 private void Form1_FormClosing(object sender, FormClosingEventArgs e) { DialogRe ...
- JAVA运行机制
这一篇我们来简单理解一下JAVA的运行机制 大概可以分为三大部分 1.编写程序 2.编译程序 3.运行程序 1.编写程序 编写程序就是我们前面说的源代码 这些源代码都有特殊的语法 例如main函数 他 ...
- Git-补丁文件交互
版本库间的交互是通过git push和/或git pull命令实现的,这是Git最主要的交互模式,但并不是全部.使用补丁文件是另外一种交互方式,适用于参与者众多的大型项目进行分布式开发. 创建补丁 G ...
- Python os.walk() 简介
Table of Contents 1. os.walk目录遍历 1.1. os.walk 1.2. 例子 1.2.1. 测试topdown 1.2.2. 运行时修改遍历目录 2. 参考资料 os.w ...
- 20145202马超《java程序设计》第一周学习总结
这两天的学习让我对java有了初步的了解. 1.java是SUN公司推出的面相网络的编程语言. 特点:完全面向对象,与平台无关,跨平台性(例如c++只能在windows上执行,然而java并没有这些限 ...
- CSS3 Shape ---使用形状改变旁边内容的布局
注意 本文所实现的功能,在浏览器的支持上并不好,除chrome浏览器外其余的大部分浏览器均不支持,虽然可以使用polyfill解决,但也不能很好的支持,有时也会出错 polyfill使用方法 下载po ...
- 简洁好看的form样式收藏
本文转载自 http://www.laozuo.org/3495.html 为了方便自己查阅所以搬运过来,如有侵权希望原作者联系我删除不要突然去法院告我呀! 颜色样式啥的都可以根据需求自己调整的,这些 ...
- 《Java程序员由笨鸟到菜鸟》
<Java程序员由笨鸟到菜鸟> 在众多朋友的支持和鼓励下,<Java程序员由菜鸟到笨鸟>电子版终于和大家见面了.本电子书涵盖了从java基础到javaweb开放框架的大部分内容 ...
- 剑指Offer - 九度1349 - 数字在排序数组中出现的次数
剑指Offer - 九度1349 - 数字在排序数组中出现的次数2013-11-23 00:47 题目描述: 统计一个数字在排序数组中出现的次数. 输入: 每个测试案例包括两行: 第一行有1个整数n, ...