九省联考2018D1T2 IIIDX

29人阅读 评论(0) 收藏 举报
分类:

链接

很容易发现,歌曲间的关系构成了一棵树,于是O(n)的贪心算法也就是显然的。

但是我们对贪心带来的55~60分不满意,鉴于这个题是个nlogn范围,所以还是用数据结构吧。

很容易发现,题目给出的n首歌的难度顺序不会影响最终答案,所以首先对这个难度值从大到小排序

不过树还是要构造的,接下来预处理出每个节点的子树大小

之后,每次找一个最靠左的位置,使得这个位置左边足够放下当前节点的子树。如果有多个值相同,就放到最右边的值那里。

上面是最关键的一句话,想到这里,就突破了贪心狭隘的思路,并取得了成功的一半。

利用线段树维护每个位置左边(包括自身)还能放多大的子树,初始为1, 2, 3 ... n。

记录一个same数组表示与当前数字相同的值最靠右边的位置,然后每次查找时在线段树上二分,之后再放到最右边那里,记为pos。

放完之后,更新线段树,因为放了一棵树,所以使得pos位置和pos右边的所有位置左边的空间减少了当前节点的子树大小,就对线段树进行区间减操作。

时间复杂度O(nlogn),空间复杂度O(n)。

#include <iostream>
#include <algorithm>
#include <cstdio>

const int maxn = 5e5 + 7;

using namespace std;

int a[maxn];
int fa[maxn];
int ans[maxn];
int size[maxn];
int same[maxn];
int st[maxn << 2]; //线段树维护最小值
int add[maxn << 2];

inline int read()
{
    int X = 0; char ch = 0;
    while (ch < '0' || ch > '9') ch = getchar();
    while (ch >= '0' && ch <= '9') X = (X << 3) + (X << 1) + ch - '0', ch = getchar();
    return X;
}

inline bool cmp(int x, int y)
{
    return x > y;
}

inline void pushup(int rt)
{
    st[rt] = min(st[rt << 1], st[rt << 1 | 1]);
}

void build(int l, int r, int rt)
{
    if (l == r) {
        st[rt] = l; //初始为1 -> n的序列
        return;
    }
    int mid = (l + r) >> 1;
    build(l, mid, rt << 1);
    build(mid + 1, r, rt << 1 | 1);
    pushup(rt);
}

inline void pushdown(int rt)
{
    if (add[rt]) {
        st[rt << 1] += add[rt];
        st[rt << 1 | 1] += add[rt];
        add[rt << 1] += add[rt];
        add[rt << 1 | 1] += add[rt];
        add[rt] = 0;
    }
}

void update(int x, int y, int z, int l, int r, int rt)
{
    if (l >= x && r <= y) {
        st[rt] += z;
        add[rt] += z;
        return;
    }
    pushdown(rt);
    int mid = (l + r) >> 1;
    if (x <= mid) update(x, y, z, l, mid, rt << 1);
    if (y > mid) update(x, y, z, mid + 1, r, rt << 1 | 1);
    pushup(rt);
}

int find(int x, int l, int r, int rt) //线段树中的二分查找
{
    if (l == r) return l + (st[rt] < x);
    pushdown(rt);
    int ls = rt << 1, rs = ls | 1, mid = (l + r) >> 1;
    if (x <= st[rs]) return find(x, l, mid, ls);
    return find(x, mid + 1, r, rs);
}

int main(void)
{
    int n = read();
    double k;
    cin >> k;
    for (register int i = 1; i <= n; i++) a[i] = read();
    sort(a+1, a+n+1, cmp);
    for (register int i = n-1; i; i--) if (a[i] == a[i+1]) same[i] = same[i+1] + 1; //每个数与它右边连续几个数相同
    for (register int i = 1; i <= n; i++) fa[i] = int(i / k), size[i] = 1;
    for (register int i = n; i; i--) size[fa[i]] += size[i]; //预处理子树大小
    build(1, n, 1);
    for (register int i = 1; i <= n; i++) {
        if (fa[i] != fa[i-1]) update(ans[fa[i]], n, size[fa[i]] - 1, 1, n, 1); //维护单调性以保证二分查找的正确性
        int pos = find(size[i], 1, n, 1);
        pos += same[pos]; //传送到最右边相同值位置
        same[pos]++; //因为一个位置不能重复使用多次,所以第一遍传送到最右值之后,第二遍要传送到次右值,以此类推
        pos -= same[pos] - 1; //往回跳
        ans[i] = pos;
        update(pos, n, -size[i], 1, n, 1); //更新
    }
    for (register int i = 1; i <= n; i++) printf("%d ", a[ans[i]]);
    
    return 0;
}

查看评论

终极版C语言(九)

-
  • 1970年01月01日 08:00

九省联考2018D1T1 一双木棋

链接可以观察到,整个对局过程中的任意时刻,棋盘总是被一条从左下到右上的轮廓线拆分成有子和无子的两部分。因此,我们可以考虑轮廓线dp,从左下角开始,向上的边为1,向右的边为0。设f[sta]表示当状态为...
  • star_city_7
  • star_city_7
  • 2018-04-15 15:10:42
  • 65

九省联考2018D1T3 秘密袭击

链接又是一道经典的暴力碾标算。对每个点分别贡献最后加一块就好了。假如当前正在计算s的贡献,设f[i][j]代表包含从s到i的路径且使得s为第j大的连通块个数,进行简单的树上dp,s最终带来的贡献就是f...
  • star_city_7
  • star_city_7
  • 2018-04-15 20:34:07
  • 72

[九省联考2018] iiidx

给定一颗nnn个点的有根树,和nnn权值d1...dnd1...dnd_1 ... d_n。将每个权值分配个每个节点,要求使父亲的权值小于等于儿子的权值。依次最大化1,2,3...n1,2,3...n...
  • tata_d2
  • tata_d2
  • 2018-04-09 19:29:06
  • 133

[九省联考 2018] iiidx

题目描述: 给出一个序列 重新安排序列的下标 使得 di&amp;lt;=di/kdi&amp;lt;=di/kd_ididid_i不相同的情况成立 比如 4 2.0 1 1 1 2 ...
  • qq_35914587
  • qq_35914587
  • 2018-04-09 18:42:50
  • 121

BZOJ5249 [2018多省省队联测]IIIDX(神奇的贪心)

题目链接:BZOJ 5249题目大意:n(n
  • XHRlyb
  • XHRlyb
  • 2018-04-11 11:24:44
  • 105

[SHOI 2018] bzoj5249 IIIdx [贪心]

Description: 不想讲。 Solution: 和bzoj4010bzoj4010bzoj4010一样的想法,每次把较小的数尽量往后放。 权值线段树维护当前子树大小,然后每次求出每...
  • pocket_lengend
  • pocket_lengend
  • 2018-04-14 10:56:45
  • 37

#2472. 「九省联考 2018」IIIDX

一眼思路的题… 就是比较难写.. 考虑一个点必须小于其 ⌊idk⌋⌊idk⌋ \lfloor \frac{id}{k} \rfloor 那么容易想出一个树形结构,每个点都大于其父亲. 那么对于一...
  • Tgotp
  • Tgotp
  • 2018-04-15 15:15:16
  • 54

[贪心 线段树] LOJ#2472. 「九省联考 2018」IIIDX

从1到n枚举,逐位确定。 首先可以把关系树建出来,一个点的权值要大于等于父节点的权值。 如果没有相同数字的,第 iii 以及它子树种的点会选择 [n−sizei+1,n][n−sizei+1,n]...
  • Coldef
  • Coldef
  • 2018-04-07 21:29:41
  • 50

洛谷4364 [九省联考2018]IIIDX

标签:线段树 题目 题目传送门 题目背景 Osu 听过没?那是Konano 最喜欢的一款音乐游戏,而他的梦想就是有一天自己也能做个独特酷炫的音乐游戏。现在,他在世界知名游戏公司KONMAI...
  • qwerty1125
  • qwerty1125
  • 2018-04-10 14:21:16
  • 25
    个人资料
    等级:
    访问量: 0
    积分: 40
    排名: 0
    文章存档