UVA_11525 树状数组的活用 二分

我们知道1——k有K!种排列,现在给定k和n,要你按字典序输出 第n种排列的数列

而且题目给的 n是 n=S1(k-1)!+S2(k-2)!+...+Sk-1*1!+Sk*0!(0=<Si<=k-i),

k最大为50000,直接算出来不可能,我发现这个n的表达式很有意思,明显(k-1)!就是表示第一次除第一个以外,剩下k-1个数的排列个数,乘一个S1就说明之前用了多少次这种排列了,根据这个 再手算了一下,发现就是,每次找第Sk个数,输出,当然已经访问过的数就要T出去

这很明显就是树状数组 (或者线段树的单点修改和查询)功能,先初始化每个都是大小为1,然后每次二分找第Sk个,找到之后,把该位置置为-1,消除该位的影响,继续找,继续输出即可。你看题目里给定的S的范围也就是顺应这个,故意把剩下几个数,S就恰好限定在这个里面

发现自己二分写的还不是很熟,一开始还搞了一下子,是用mid还是L做结果呢 最后在我的写法里被证明是用L做结果

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 50000+10
using namespace std;
int A[N];
int n;
int lowbit(int x)
{
    return x&(-x);
}
void add(int x,int v)
{
    while (x<=n){
        A[x]+=v;
        x+=lowbit(x);
    }
}
void init()
{
    for (int i=1;i<=n;i++){
        add(i,1);
    }
}
int query(int x)
{
    int ret=0;
    while (x>0){
        ret+=A[x];
        x-=lowbit(x);
    }
    return ret;
}
int main()
{
    int t;
    scanf("%d",&t);
    while (t--)
    {
      scanf("%d",&n);
      init();
      for (int i=1;i<=n;i++){
        int a;
        scanf("%d",&a);
        int L=1,R=n,mid;
        while (L<R)
        {
            mid=(L+R)>>1;
            int tmp=query(mid);
            //if (tmp==a+1) break;
            if (tmp<a+1) L=mid+1;
            else R=mid;
        }
        //cout<<"@@"<<mid<<endl;
        add(L,-1);
        printf("%d",L);
        if (i<n) putchar(‘ ‘);
      }
      puts("");
    }
    return 0;
}

UVA_11525 树状数组的活用 二分

时间: 2024-11-08 08:59:31

UVA_11525 树状数组的活用 二分的相关文章

数据结构1——树状数组

一.相关定义 树状数组 获取数组中连续n个数的和 修改数组中某点的值 时间复杂度:O(logn) 小结:树状数组的强项在于对数组进行维护查询(如,修改某点的值.求某个区间的和).当然,数据规模不大的时候,对于修改某点的值是非常容易的,复杂度是O(1),但是对于求一个区间的和就要扫一遍了,复杂度是O(N),如果实时的对数组进行M次修改或求和,最坏的情况下复杂度是O(M*N),当规模增大后这是划不来的!而树状数组干同样的事复杂度却是O(M*logN). 二.算法描述 列出即将出现的知识定义: low

树状数组详解(图形学算法)

目录 一.从图形学算法说起 1.Median Filter 概述 2.r pixel-Median Filter 算法 3.一维模型 4.数据结构的设计 5.树状数组华丽登场 二.细说树状数组 1.树 or 数组? 2.结点的含义 3.求和操作 4.更新操作 5.lowbit函数O(1)实现 6.小结 三.树状数组的经典模型 1.PUIQ模型 2.IUPQ模型 3.逆序模型 4.二分模型 5.再说Median Filter 6.多维树状数组模型 四.树状数组题集整理 一.从图形学算法说起 1.M

bzoj1146整体二分+树链剖分+树状数组

其实也没啥好说的 用树状数组可以O(logn)的查询 套一层整体二分就可以做到O(nlngn) 最后用树链剖分让序列上树 1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 inline int read() 7 { 8 int x=0,f=1,ch=getchar(); 9 while(ch<

SYSU-5, POJ 2131, 树状数组+二分

题目大意:给出n个人,顺序对位置进行请求,如果第i个人请求的位置上有人,则让这个人顺延,如果顺延的位置继续有人,递归进行,问最后所有人的位置. 解:这题貌似可以用平衡树+并查集搞定,但是我队友强烈安利树状数组的做法.赛场上没出,赛后结合discuz想了一下,作一下处理. 首先如果是一个请求第a[i]个有空位置的问题,那么这个问题显然可以用树状数组维护前缀和即可.所以我们现在考虑将原问题转化成这个问题. 考虑终态,把没有人的位置去掉,剩下的n个座位排在一起,显然转化成上面模型的形式 第i个询问时,

HDU 2852 KiKi&#39;s K-Number (树状数组 &amp;&amp; 二分)

题意:给出对容器的总操作次数n, 接下来是这n个操作.这里对于一个容器提供三种操作, 分别是插入.删除和查找.输入0  e表示插入e.输入1  e表示删除e,若元素不存在输出No Elment!.输入2  e  k表示查找比e大且第k大的数, 若不存在则输出Not Find! 分析:这里考虑树状数组做的原因是在第三个操作的时候, 只要我们记录了元素的总数, 那通过求和操作, 便能够高效地知道到底有多少个数比现在求和的这个数要大, 例如 tot - sum(3)就能知道整个集合里面比3大的数到底有

hdu-5493 Queue(二分+树状数组)

题目链接: Queue Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 1093    Accepted Submission(s): 566 Problem Description N people numbered from 1 to N are waiting in a bank for service. They all stan

poj 2892(二分+树状数组)

Tunnel Warfare Time Limit: 1000MS   Memory Limit: 131072K Total Submissions: 7749   Accepted: 3195 Description During the War of Resistance Against Japan, tunnel warfare was carried out extensively in the vast areas of north China Plain. Generally sp

13年山东省赛 Boring Counting(离线树状数组or主席树+二分or划分树+二分)

转载请注明出处: http://www.cnblogs.com/fraud/          ——by fraud 2224: Boring Counting Time Limit: 3 Sec  Memory Limit: 128 MB Description In this problem you are given a number sequence P consisting of N integer and Pi is the ith element in the sequence.

区间查询/二分/树状数组/伸展树

一.手写二分 #include <bits/stdc++.h> int a[5] = {5, 3, 3, 2, 1}; template <class T> inline T bfind(T r, T key) { T l = 1, m, k, flag = 0; while(l != r) { m = (r + l) / 2; if(a[m] > key) l = m + 1; if(a[m] < key) r = m - 1; if(a[m] == key) { r