uva 11525(线段树)
题目链接:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2520
题意:有一个排列1~k,求第n个排列,其中n为 ,K(1≤K≤50000),S1, S2 ,…, Sk.(0≤Si≤K-i).
分析:这道题目乍看之下没有什么好的思路,k!太大了,但是仔细看一看就会发现n和康托展开式很类似
如果不知道康托展开的话请看:http://www.doc88.com/p-293361248346.html
http://blog.csdn.net/morgan_xww/article/details/6275460
要求第n个全排列,这不就是逆康托展开吗?
没错,仔细对比逆康托展开的推理过程就会发现,其实第n个全排列中的第i个数就是该排列中未出现过的比si大的第一个数。
比如:2 1 0 则比2大的第一个数是3,3未出现过,所以第一个数是3
比1大的第一个数是2,2未出现过,所以第二个数是2
比0大的第一个数是1,1未出现过,所以第三个数是1
所以结果为3 2 1
再比如:1 0 0 则比1大的第一个数是2,2未出现过,所以第一个数是2
比0 大的第一个数是1,1未出现过,所以第二个数是1
比0大的第一个数是1,但是1,2已经出现过了,所以第三个数是3
以此类推
普通的逆康托展开复杂度是O(n^2),这样对于k<=50000来说肯定是会超时的,可以用线段树(二分+树状数组)优化。
由上面的分析可知,
解法1:
线段树的具体做法同样是把 [1, K] 的数置成 1. 此时每条线段的权所代表的意义为在该区间内还有多少个数可以用。查找大于si的第一个未出现过的数,然后把这个数赋为0。 查找的时候如果左线段可用的数大于等于当前我们查找的数, 说明我们要找的数在左线段, 进入左线段, 查找的数不变; 否则说明在右线段, 进入右线段, 查找的数减去左线段可用的数的数目. 递归返回条件为当前节点代表的线段为单位线段(说明我们已经找到了)。
AC代码如下:
#include<stdio.h>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int maxn=+;
int tree[maxn<<],ans;
void PushUp(int rt)
{
tree[rt]=tree[rt<<]+tree[rt<<|];
}
void build(int l,int r,int rt)
{
if(l==r)
{
tree[rt]=;
return ;
}
int m=(l+r)>>;
build(lson);
build(rson);
PushUp(rt);
}
void update(int p,int x,int l,int r,int rt)
{
if(l==r)
{
tree[rt]=x;
ans=l;
return ;
}
int m=(l+r)>>;
if(p<=tree[rt<<])
update(p,x,lson);
else
update(p-tree[rt<<],x,rson);
PushUp(rt);
}
int main()
{
int t,n,i,x;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
build(,n,);
for(i=;i<n;i++)
{
scanf("%d",&x);
update(x+,,,n,);
printf("%d",ans);
if(i!=n-)
printf(" ");
}
printf("\n");
}
return ;
}
解法2:
树状数组的具体做法是初始把 [1, K] 的数置成 1, 然后根据所给 S 数组, 去查找前缀和, 前缀和 sum[N] 代表 [1, N] 内有多少个数可以用. 注意前缀和是单调不减的, 因此我们可以二分, 查找第一个等于我们要找的数/的那个下标, 便是全排列当前位的数, 然后把这个下标里的数置成 0, 同时更新树状数组.
AC代码如下:
#include<stdio.h>
#include<string.h>
const int maxn=+;
int c[maxn],num[maxn];
int n;
int lowbit(int x)
{
return x&(-x);
}
void update(int x,int num)
{
while(x<=n)
{
c[x]+=num;
x+=lowbit(x);
}
}
int sum(int x)
{
int ret=;
while(x>)
{
ret+=c[x];
x-=lowbit(x);
}
return ret;
}
int binary(int x)
{
int low=,high=n;
while(low<=high)
{
int m=(low+high)>>;
int cnt=sum(m);
if(cnt==x)
{
if(num[m])
return m;
else
high=m-;
}
else if(cnt<x)
low=m+;
else
high=m-;
}
return ;
}
int main()
{
int t,i,x;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
memset(c,,sizeof(c));
for(i=;i<=n;i++)
num[i]=;
for(i=;i<=n;i++)
update(i,);
for(i=;i<n;i++)
{
scanf("%d",&x);
int cnt=binary(x+);
update(cnt,-);
num[cnt]=;
printf("%d",cnt);
if(i!=n-)
printf(" ");
}
printf("\n");
}
return ;
}
uva 11525(线段树)的更多相关文章
- UVA 11297 线段树套线段树(二维线段树)
题目大意: 就是在二维的空间内进行单个的修改,或者进行整块矩形区域的最大最小值查询 二维线段树树,要注意的是第一维上不是叶子形成的第二维线段树和叶子形成的第二维线段树要 不同的处理方式,非叶子形成的 ...
- UVa 11992 (线段树 区间修改) Fast Matrix Operations
比较综合的一道题目. 二维的线段树,支持区间的add和set操作,然后询问子矩阵的sum,min,max 写完这道题也是醉醉哒,代码仓库里还有一份代码就是在query的过程中也pushdown向下传递 ...
- UVa 1400 (线段树) "Ray, Pass me the dishes!"
求一个区间的最大连续子序列,基本想法就是分治,这段子序列可能在区间的左半边,也可能在区间的右半边,也有可能是横跨区间中点,这样就是左子区间的最大后缀加上右子区间的最大前缀之和. 线段树维护三个信息:区 ...
- UVA 11992 线段树
input r c m r<=20,1<=m<=20000 m行操作 1 x1 y1 x2 y2 v add v 2 x1 y1 x2 y2 v s ...
- uva 1513(线段树)
题目链接:1513 - Movie collection 题意:有一堆电影,按1-n顺序排,有m次操作,每次询问第ai个电影之前有多少个电影,然后将其抽出放在堆顶. 分析:线段树应用. 因为每次查询后 ...
- uva 12086 线段树or树状数组练习
题目链接 https://vjudge.net/problem/34215/origin 这个题就是线段树裸题,有两种操作,实现单点更新和区间和的查找即可,这里第一次学习使用树状数组完成. 二者相 ...
- UVa 12299 线段树 单点更新 RMQ with Shifts
因为shift操作中的数不多,所以直接用单点更新模拟一下就好了. 太久不写线段树,手好生啊,不是这错一下就是那错一下. PS:输入写的我有点蛋疼,不知道谁有没有更好的写法. #include < ...
- UVA 12299 线段树 ( 单点跟新 , 区间查询)
题目链接:题意:在传统的RMQ的基础上加上一个操作:shift(i1,i2,i3...ik),表示将这些元素,依次向左移动一位(训练指南247页) #include <iostream> ...
- UVA 11992 ——线段树(区间修改)
解题思路: 将矩阵每一行建立一棵线段树,进而变成一维问题求解.注意数组要开 4*N 代码如下: #include <iostream> #include <cstdio> #i ...
随机推荐
- [VB.NET][C#]二维向量的基本运算
前言 在数学中,几何向量指具有大小(Magnitude)和方向的几何对象,它在线性代数中经由抽象化有着更一般的概念.向量在编程中也有着及其广泛的应用,其作用在图形编程和游戏物理引擎方面尤为突出. 基于 ...
- Python distribute到底使用package_data还是MANIFEST.in?
今天看Flask的文档,里面提到如何通过distribute发布你自己的Python包.讲包含文件的时候,提到要用MANIFEST.in并将include_package_data设置为True. 由 ...
- Micro:bit篮球小游戏
尝试用Micro:bit制作一款篮球游戏,材料是利用一些纸箱跟生活周遭可以取得的加上Micro;bit,打造出一个好玩的篮球游戏,制作过程也十分简单. 材料清单 先制作篮板. 接着制作篮球架体. 制作 ...
- HTTP 请求/响应报文结构
请求报文和响应报文都是由以下4部分组成: 1.请求行/响应行 2.请求头/响应头 3.空行 4.消息主体(请求体/响应体) 请求报文结构 请求行 格式为:Method Request-URI HTTP ...
- Vue随性小笔记
1 前端MVC 和 后端MVC不同: 可以看出前端MVC其实为了解决前端复杂js模块化的问题,从后端MVC的V分离出来的 2 MVC / MVP / MVVM 三者区别 Model View ...
- day01_概念
1 网络分类: 1 按照范围: - 局域网:范围很小的网络,如一间办公室,一个公司 - 城域网:大致城市范围内的网络,半径几公里到几十公里 - 广域网:比城域网范围更大的 2 网络衡量标准 1 传输速 ...
- lua中table的常用方法
转载:https://blog.csdn.net/Fenglele_Fans/article/details/83627021 1:table.sort() language = {"lua ...
- NO17--vue父子组件间单向数据流的解决办法
在上一篇中讲解了父子组件之间是如何传值的,如果子组件需要改变传过来的数据供自己使用,或者想在子组件中改变传过来的数据并同步到父组件,那么直接改肯定是不行的,如果你这么做了,Vue 会在控制台给出警告. ...
- 013-- mysql常用的查询优化方法
浅谈MySQL中优化sql语句查询常用的30种方法 1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句 ...
- 第七章 用户输入和while循环
7.1函数input()的工作原理 函数默认输入为字符串string,如果需使用数字,需用int进行类型转换 7.2 while循环 while是根据条件的真假判断是否进入执行 使用标志: 使用bre ...