UVA11525 - Permutation(线段树)

题目链接

题目大意:给定一个K,将数字1-K这个序列全排列(K!种),然后给你一个公式让你求的N,问第N小的数字排列。

解题思路:因为这个求N的公式很特别,Si(K - i)!这个其实就是确定了第i个数是第(Si + 1)大的数字。例如K = 3, S序列 3 2 1,那么3
(3 - 1)!就说明第一个数是3。接着2 (2 - 1)!说明第二个数是2(因为3已经用了)。所以这题是要查询第(si + 1)大的数,并且需要将用过的数更新。

代码:

#include <cstdio>
#include <cstring>

const int N = 5e4 + 5;

#define lson(x) (2*(x))
#define rson(x) (2*(x) + 1)

struct Node {

    int l, r, v;
    void set(int l, int r, int v) {
        this->l = l;
        this->r = r;
        this->v = v;
    }
}node[4 * N];

void build (int u, int l, int r) {

    if (l == r)
        node[u].set(l, r, 1);
    else {

        int m = l + (r - l) / 2;
        build(lson(u), l, m);
        build(rson(u), m + 1, r);
        node[u].set(l, r, node[lson(u)].v + node[rson(u)].v);
    }
}

int Query (int u, int k) {

    if (node[u].l == node[u].r)
        return node[u].l;
    if (k > node[lson(u)].v)
        return Query(rson(u), k - node[lson(u)].v);
    else
        return Query(lson(u), k);
}

void Update (int u, int p, int v) {

    if (node[u].l == node[u].r)
        node[u].v = v;
    else {

        int m = node[u].l + (node[u].r - node[u].l) / 2;
        if (p <= m)
            Update (lson(u), p, v);
        else
            Update (rson(u), p, v);
        node[u].v = node[lson(u)].v + node[rson(u)].v;
    }
}

int main () {

    int T, K, num, p;
    scanf ("%d", &T);
    while (T--) {

        scanf ("%d", &K);
        build(1, 1, K);
        for (int i = 0; i < K; i++) {

            scanf ("%d", &num);
            p = Query (1, num + 1);
            if (i != K - 1)
                printf ("%d ", p);
            else
                printf ("%d\n", p);
            Update(1, p, 0);
        }
    }
    return 0;
}

时间: 2024-08-19 14:15:47

UVA11525 - Permutation(线段树)的相关文章

BNU 51636 Squared Permutation 线段树

Squared Permutation 最近,无聊的过河船同学在玩一种奇怪的名为“小Q的恶作剧”的纸牌游戏. 现在过河船同学手有张牌,分别写着,打乱顺序之后排成一行,位置从左往右按照标号. 接下来小Q同学会给出个操作,分为以下两种: 1.给定,交换从左往右数的第和第张牌, 2.给定,对从左往右数的第张牌,记下位置是这张牌上的数字的牌的数字,询问所有记下的数字加起来的结果. 虽然无聊的过河船同学精通四则运算,但是要完成这么大的计算量还是太辛苦了,希望你能帮他处理这些操作. Input 第一行是一个

uva 11525 - Permutation(线段树)

题目链接:uva 11525 - Permutation 题目大意:给定n和k,n给定的方式为k个si,根据公式计算出n,求一个由1~k组成的长度为k的序列的第n个排序 解题思路:根据公式的性质,等于对于每个位置找当前状态下第si小的数.线段树子节点均为1,维护和,查询时传入参数查找即可. #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int ma

[Codeforces 1295E]Permutation Separation(线段树+贪心)

[Codeforces 1295E]Permutation Separation(线段树+贪心) 题面 给出一个排列\(p_1,p_2,...p_n\).初始时你需要选择一个位置把排列分成左右两个.然后在两个序列间移动元素使得左边序列的所有元素都比右边的所有元素小.给出每个元素\(p_i\)从一个序列移动到另一个序列的代价\(a_i\). 分析 显然最后得到的序列是小的数在一边,大的数在另一边.设从值为\(i\)的元素处分开之后移动代价为\(ans_i\). 一开始假设所有数都移到右边序列,那么

UVA 11525 Permutation ——(线段树,脑筋急转弯)

只要注意到对于譬如:S1*(k-1)! 因为后面k-1个数字的全排列个数刚好是(k-1)!,那么第一个数字就是没有取过的数字的第(S1+1)个即可.取走这个数字以后这个数字就不能再用了,依次类推即可得到整个排列了. 那么随便用线段树维护一下即可. 代码如下: 1 #include <stdio.h> 2 #include <algorithm> 3 #include <string.h> 4 #define t_mid (l+r>>1) 5 #define

[CSP-S模拟测试]:Permutation(线段树+拓扑排序+贪心)

题目描述 你有一个长度为$n$的排列$P$与一个正整数$K$你可以进行如下操作若干次使得排列的字典序尽量小对于两个满足$|i−j|\geqslant K$且$|P_i−P_j|=1$的下标$i$与$j$,交换$P_i$与$P_j$ 输入格式 第一行包括两个正整数$n$与$K$第二行包括$n$个正整数,第$i$个正整数表示$P_i$ 输出格式 输出一个新排列表示答案输出共$n$行,第$i$行表示$P_i$ 样例 样例输入: 8 34 5 7 8 3 1 2 6 样例输出: 12675348 数据范

hdu 1394 Minimum Inversion Number(这道题改日我要用线段树再做一次哟~)

Problem Description The inversion number of a given number sequence a1, a2, ..., an is the number of pairs (ai, aj) that satisfy i < j and ai > aj. For a given sequence of numbers a1, a2, ..., an, if we move the first m >= 0 numbers to the end of

HDU1394 Minimum Inversion Number 线段树+数学

Problem Description The inversion number of a given number sequence a1, a2, -, an is the number of pairs (ai, aj) that satisfy i < j and ai > aj. For a given sequence of numbers a1, a2, -, an, if we move the first m >= 0 numbers to the end of the

hdu1394线段树点修改,区间求和

Problem Description The inversion number of a given number sequence a1, a2, ..., an is the number of pairs (ai, aj) that satisfy i < j and ai > aj. For a given sequence of numbers a1, a2, ..., an, if we move the first m >= 0 numbers to the end of

Codeforces Round #393 (Div. 2) E题Nikita and stack(线段树)解题报告

Nikita has a stack. A stack in this problem is a data structure that supports two operations. Operation push(x) puts an integer x on the top of the stack, and operation pop() deletes the top integer from the stack, i. e. the last added. If the stack

HDOJ 1394 Minimum Inversion Number 求循环串的最小逆序数(暴力&amp;&amp;线段树)

Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 14879    Accepted Submission(s): 9082 Problem Description The inversion number of a given number sequence a1, a2, ..., a