Codeforces 474E - Pillars

一眼看上去非常像最长不下降子序列。

然后比赛的时候对每个答案长度为k的序列,维护最后一个数的最大值和最小值。

当时不知道为什么认为从长度最长倒推至前面不会太长,于是心满意足地敲了个O(n^2)。结果T了。。。

正确的做法应该用线段树维护,搜起来就是log(n),总的就是O(N*logN);

用非递归的方法写的

只用了77ms

在目前(2014/10/7) 是最快的。

#include <iostream>
#include <cstdio>
using namespace std;

#define ll long long

const int INF = 300009;

struct node {
    ll key;
    int pos;
} dtmin[INF], dtmax[INF];
ll n, d, t, x, M;
ll pre[INF];
int f[INF], ans[INF], namax[INF], namin[INF];

inline int Searchmax (int x, ll k) {
    while (dtmax[x].key - k >= d) {
        if (x > M) return dtmax[x].pos;
        if (dtmax[x << 1 | 1].key - k >= d) x = x << 1 | 1;
        else
            x = x << 1;
    }
    return 0;
}
inline int Searchmin (int x, ll k) {
    while (k - dtmin[x].key >= d) {
        if (x > M) return dtmin[x].pos;
        if (k - dtmin[x << 1 | 1].key >= d) x = x << 1 | 1;
        else
            x = x << 1;
    }
    return 0;
}

inline void modify (int x, ll k, int i) {
    if (dtmax[x + M].key < k) namax[x] = i, dtmax[x + M].key = k;
    for (int t = x + M; dtmax[t >> 1].key < k && t > 0; t >>= 1)
        dtmax[t >> 1] = dtmax[t];

    if (dtmin[x + M].key > k) namin[x] = i, dtmin[x + M].key = k;
    for (int t = x + M; dtmin[t >> 1].key > k && t > 0; t >>= 1)
        dtmin[t >> 1]  = dtmin[t];
}

int main() {
    ios::sync_with_stdio (false);
    cin >> n >> d;
    cin>>x;
    M = n;
    int tem = 0;
    for (int k = M; k; tem++, k >>= 1) ;
    M = 1 << tem;
    for (int i = 0; i < (M << 1) + 10; i++) {
        dtmax[i].key = 0 , dtmin[i].key = (1LL << 60);
        dtmax[i].pos = i - M, dtmin[i].pos = i - M;
    }
    dtmax[1].key = dtmin[1].key = x;
    t = f[1] = 1;
    modify (t, x, 1);
    for (int i = 2,k; i <= n; i++) {
        cin >> x;
        if (k = Searchmax (1, x) )
            if (f[i] < k + 1)
                f[i] = k  + 1, pre[i] = namax[k];

        if ((k = Searchmin (1, x)))
            if (f[i] < k + 1)
                f[i] = k  + 1, pre[i] = namin[k];

        if (f[i] > t) t = f[i];
        if (f[i] == 0)   f[i] = 1;
        modify (f[i], x, i);
    }
    cout << t << endl;
    int p = -1;
    for (int i = 1; i <= n; i++)  if (f[i] == t) { p = i; break; }
    for (int i = t; i; i--)
        ans[i] = p, p = pre[p];
    for (int i = 1; i <= t; i++)
        cout << ans[i] << ‘ ‘;
}

时间: 2024-10-05 05:31:55

Codeforces 474E - Pillars的相关文章

Codeforces 474E Pillars(论数据的重要性)

今天做到这道题,一看是一道很水的最长不下降序列吧,但是数据超级大,怎么办,突发奇想,因为每一次都要和前面比,那么需要从第一个状态推现在的状态,那么有数据比较水,也许前面的600个状态就可一推理到,那么直接从他的钱600个状态推就水过了 #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> using names

【CF】474E Pillars

H的范围是10^15,DP方程很容易想到.但是因为H的范围太大了,而n的范围还算可以接受.因此,对高度排序排重后.使用新的索引建立线段树,使用线段树查询当前高度区间内的最大值,以及该最大值的前趋索引.线段树中的结点索引一定满足i<j的条件,因为采用从n向1更新线段树结点.每次线段树查询操作就可以得到argmax(dp[L, R]),很据不等式很容易得到L和R的范围. 1 /* 474E */ 2 #include <iostream> 3 #include <string>

线段树详解 (原理,实现与应用)

线段树详解 By 岩之痕 目录: 一:综述 二:原理 三:递归实现 四:非递归原理 五:非递归实现 六:线段树解题模型 七:扫描线 八:可持久化 (主席树) 九:练习题 一:综述 假设有编号从1到n的n个点,每个点都存了一些信息,用[L,R]表示下标从L到R的这些点. 线段树的用处就是,对编号连续的一些点进行修改或者统计操作,修改和统计的复杂度都是O(log2(n)). 线段树的原理,就是,将[1,n]分解成若干特定的子区间(数量不超过4*n),然后,将每个区间[L,R]都分解为 少量特定的子区

【CF 474E】Pillars

[CF 474E]Pillars 离散化+线段树dp 大半夜写出来了...好长好长好长好长好挫--先把高度排序离散化 我又开了个哈希数组用来查某点对应离散后的点 然后遍历每个点时二分出满足题意的区间(1~h-d)(h+d~max) 然后线段树查两个区间当前最大长度的序列 累计到当前点对应的树内点 同时更新他的父亲点们的最大长度 再把之前最大长度的末尾作为当前点的前驱 如果没有就用当前点自己做前驱 最后输出树根存的节点的前驱们(即为树内最长的序列) 各种节点哈希的有点混乱--代码--看乱了就别看了

Educational Codeforces Round 69 (Rated for Div. 2) B - Pillars

Educational Codeforces Round 69 (Rated for Div. 2) B - Pillars There are n pillars aligned in a row and numbered from 1 to n. Initially each pillar contains exactly one disk. The i-th pillar contains a disk having radius ai. You can move these disks

【codeforces 718E】E. Matvey&#39;s Birthday

题目大意&链接: http://codeforces.com/problemset/problem/718/E 给一个长为n(n<=100 000)的只包含‘a’~‘h’8个字符的字符串s.两个位置i,j(i!=j)存在一条边,当且仅当|i-j|==1或s[i]==s[j].求这个无向图的直径,以及直径数量. 题解:  命题1:任意位置之间距离不会大于15. 证明:对于任意两个位置i,j之间,其所经过每种字符不会超过2个(因为相同字符会连边),所以i,j经过节点至多为16,也就意味着边数至多

Codeforces 124A - The number of positions

题目链接:http://codeforces.com/problemset/problem/124/A Petr stands in line of n people, but he doesn't know exactly which position he occupies. He can say that there are no less than a people standing in front of him and no more than b people standing b

Codeforces 841D Leha and another game about graph - 差分

Leha plays a computer game, where is on each level is given a connected graph with n vertices and m edges. Graph can contain multiple edges, but can not contain self loops. Each vertex has an integer di, which can be equal to 0, 1 or  - 1. To pass th

Codeforces Round #286 (Div. 1) A. Mr. Kitayuta, the Treasure Hunter DP

链接: http://codeforces.com/problemset/problem/506/A 题意: 给出30000个岛,有n个宝石分布在上面,第一步到d位置,每次走的距离与上一步的差距不大于1,问走完一路最多捡到多少块宝石. 题解: 容易想到DP,dp[i][j]表示到达 i 处,现在步长为 j 时最多收集到的财富,转移也不难,cnt[i]表示 i 处的财富. dp[i+step-1] = max(dp[i+step-1],dp[i][j]+cnt[i+step+1]) dp[i+st