• [bzoj2131] 免费的馅饼


    Description

    Input

    第一行是用空格隔开的二个正整数,分别给出了舞台的宽度W(1到10^8之间)和馅饼的个数n(1到10^5)。  接下来n行,每一行给出了一块馅饼的信息。由三个正整数组成,分别表示了每个馅饼落到舞台上的时刻t[i](1到10^8秒),掉到舞台上的格子的编号p[i](1和w之间),以及分值v[i](1到1000之间)。游戏开始时刻为0。输入文件中同一行相邻两项之间用一个空格隔开。输入数据中可能存在两个馅饼的t[i]和p[i]都一样。

    Output

    一个数,表示游戏者获得的最大总得分。

    Sample Input

    3 4
    1 2 3
    5 2 3
    6 3 4
    1 1 5

    Sample Output

    12
    【数据规模】
    对于100%的数据,1<=w,t[i]<=10^8,1<=n<=100000。
     
    这道题真的令我印象十分特别深刻...。 在东北的时候听过 回来又听zyl讲过
    这道题是一道用线段树解决的二位偏序的$dp$问题
    dp[i]表示当前吃第$i$块馅饼所能够获得的最大价值 考虑如何转移 转移方程式是很简单的
    $dp[i] = max(dp[j] + val[i])$,$j$属于能够转移到$i$的馅饼
    那么现在需要解决的问题就是哪些馅饼能够转移到$i$号 首先$j$号馅饼一定要在$i$号馅饼之前出现
    考虑如果$j$号馅饼能够转移到$i$号   那么还需要满足式子
    $|pos[i] - pos[j]| <= 2 * (t[i] - t[j])$ 
    打开绝对值之后得到的两个化简得到两个关于$i,j$的式子 将同属性的移到等式一边得到
            $2 * t[i] - pos[i] >= 2 * t[j] - pos[j]  , 2 * t[i]  + pos[i] >= 2 * t[j] + pos[j]$
    发现这两个式子是等价的 也就是说只要同时满足上面两个式子 原始式子就一定成立
    证明:
    $1.pos[i] >= pos[j]$ 也就是说他满足了式子$1$ 原本$t[i] > t[j]$     那么$2 * t[i]$加上$pos[i]$后会比左边更大  一定成立
    第二种情况的证明是一样的 所以两只需要同时满足这两个属性就可以进行转移
    代码
    #include <bits/stdc++.h>
    using namespace std;
     
    const int N = 1e5 + 5;
    int n,m,tt[N],f[4 * N],w,dp[N];
     
    struct food {
         
        int f1,f2,val;
    }b[N];
     
    void init( ) {
         
        int t,p,val;
        scanf("%d%d",& w,& n);
        for(int i = 1;i <= n;i ++) {
            scanf("%d%d%d",& t,& p,& val);
            b[i].f1 = 2 * t + p;
            b[i].f2 = 2 * t - p;
            b[i].val = val;
            tt[i] = 2 * t + p;
        }
        sort(tt + 1,tt + n + 1);
        m = unique(tt + 1,tt + n + 1) - tt - 1;
    }
     
    void update(int o) {
         
        f[o] = max(f[2 * o],f[2 * o + 1]);
    }
     
    bool cmp(const food & a,const food & b) {
         
        return a.f2 < b.f2;
    }
     
    int query(int o,int l,int r,int L,int R) {
         
        if(l >= L && r <= R) return f[o];
        int mid = (l + r) >> 1;
        int ans = 0;
        if(L <= mid) ans = max(ans,query(2 * o,l,mid,L,R));
        if(mid < R)  ans = max(ans,query(2 * o + 1,mid + 1,r,L,R));
        return ans;
    }
     
    void modify(int o,int l,int r,int pos,int val) {
         
        if(l == r) {
            f[o] = max(f[o],val);
            return ;
        }
        int mid = (l + r) >> 1;
        if(pos <= mid) modify(2 * o,l,mid,pos,val);
        else modify(2 * o + 1,mid + 1,r,pos,val);
        update(o);
    }
     
    int main( ) {
         
        init( );
        sort(b + 1,b + n + 1,cmp);
         
        for(int i = 1;i <= n;i ++) {
            int pos = lower_bound(tt + 1,tt + m + 1,b[i].f1) - tt;
            int q = query(1,1,m,1,pos);
            dp[i] = q + b[i].val;
            modify(1,1,m,pos,dp[i]);
        }
        printf("%d",query(1,1,m,1,m));
        return 0;
    }
  • 相关阅读:
    html5基础--canvas标签元素
    html5基础--audio标签元素
    html5基础--video标签元素
    SSH Secure Shell Client中文乱码的解决方法
    Response.End() 与Response.Close()的区别
    服务器控件的返回值问题
    常用数据库操作(一)
    DataTable 读取数据库操作时去掉空格
    回车触发Button
    404页面自动跳转javascript
  • 原文地址:https://www.cnblogs.com/Rubenisveryhandsome/p/9779336.html
Copyright © 2020-2023  润新知