Light OJ 1402 (Dp + 树状数组)

来源:互联网 发布:淘宝大码女装秋装 编辑:程序博客网 时间:2024/06/07 05:26

题目:

[LINK](http://www.lightoj.com/volume_showproblem.php?problem=1402)给你一些点(SRT, R);按照SRT排序, 然后再坐标系中画出这些点, 连成一条线。线会有峰点(peak),一个点是峰点, 相邻两个点的 R 值都比它小 或 大。然后WARush 要丧病的忽略一些点,(忽略第X点后,第 X 后面的点会前移! ) 会形成新的线。 然后题目要求输出所有线条中刚好有 K 个峰点的**不同线条**的数量。

分析:

题目中 单个点 和 没有点 都算一种情况。先把所有点排序, 然后依次画图, 统计线条数。对于 第 i 个点画图时 :    枚举 K 值    当K == 0时, 我们可以得出:        上升线条 Up = [比 Ri 低的点的数目] + [总结点数] + [上升线条尾端点值比 Ri 低的数]        下降线条 Down 同理。        故Dp[k] = Up + Down + 节点node 数。    当 K > 0 时。 :        上升线条 Up(k) = [上升线条 Up(k) 中尾端点比 Ri 小的线条数] + \                       [ 下降线条 Down(k-1) 中尾端点比 Ri 小的线条数].        下降线条 Down(k) 同理。怎么求这些值? 用树状数组维护就好了。

Code:

#include <bits/stdc++.h>using namespace std;typedef unsigned int U32;const int maxn = 10000 + 131;inline int lowbit(int x) {    return x & (-x);}///树状数组struct BIT {    U32 Num[maxn];    int N;    void INIT(int n) {        N = n;        memset(Num, 0, sizeof(Num));    }    void Add(int x, U32 val) {        while(x <= N) {            Num[x] += val;            x   += lowbit(x);        }    }    U32 Sum(int x) {        U32 ret = 0;        while(x > 0) {            ret += Num[x];            x   -= lowbit(x);        }        return ret;    }    U32 Sec(int L, int R) {        return Sum(R) - Sum(L-1);    }};/// DP 状态struct State {    BIT Up, Down, Node;    void INIT(int n) {        Up.INIT(n);        Down.INIT(n);        Node.INIT(n);    }};struct Data {    int s, r;    bool operator < (const Data& a) const {        return this->s < a.s;    }};Data node[maxn];State Dp[60];int R_n[maxn];int main() {    int T;    scanf("%d",&T);    for(int kase = 1; kase <= T; ++kase) {        int n, K;        scanf("%d%d",&n, &K);        for(int i = 0; i < n; ++i) {            scanf("%d%d",&node[i].s, &node[i].r);            R_n[i] = node[i].r;        }        sort(R_n, R_n+n);        int C   = unique(R_n, R_n+n) - R_n;        int Max = -1;        for(int i = 0; i < n; ++i) {            node[i].r = lower_bound(R_n, R_n+C, node[i].r)-R_n+1;            Max       = max(Max, node[i].r);        }        sort(node, node+n);        ///离散化结束        for(int i = 0; i <= K; ++i) Dp[i].INIT(Max);        for(int i = 0; i < n; ++i) {            int h = node[i].r;            for(int k = 0; k <= K; ++k) {                //相同点会造成相同的线条, 所以要减去。                U32 Sum_Up   = -Dp[k].Up.Sec(h,h);                U32 Sum_down = -Dp[k].Down.Sec(h,h);                U32 Sum_node = -Dp[k].Node.Sec(h,h);                Sum_Up       += Dp[k].Up.Sum(h-1) + Dp[k].Node.Sum(h-1);                Sum_down     += Dp[k].Down.Sec(h+1, Max) + Dp[k].Node.Sec(h+1,Max);                if(k == 0) Sum_node++;                else {                    Sum_Up   += Dp[k-1].Down.Sum(h-1);                    Sum_down += Dp[k-1].Up.Sec(h+1, Max);                }                if(Sum_Up) Dp[k].Up.Add(h, Sum_Up);                if(Sum_down) Dp[k].Down.Add(h, Sum_down);                if(Sum_node) Dp[k].Node.Add(h, Sum_node);            }        }        U32 Ans = 0;        Ans = Dp[K].Down.Sum(Max) + Dp[K].Up.Sum(Max) + Dp[K].Node.Sum(Max);        if(K == 0) Ans ++;        printf("Case %d: %u\n",kase, Ans);    }    return 0;}
1 0
原创粉丝点击