zoukankan      html  css  js  c++  java
  • 【BZOJ】2131: 免费的馅饼

    2131: 免费的馅饼

    Time Limit: 10 Sec  Memory Limit: 259 MB
    Submit: 508  Solved: 310
    [Submit][Status][Discuss]

    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。

    HINT

     

    Source

     
    [Submit][Status][Discuss]


    HOME Back


    一道经典的二维偏序问题。至于怎么将原题目转换为二维偏序??

    首先可以将每秒走一步和两步转换为每0.5秒选择走或不走,把时间加倍。接下来考虑dp转移。能从j转移到i当且仅当ti-tj>=|pi-pj|,可以转换为两个式子:pi>=pj时,ti-pi>=tj-pj,又因为pi-pj此时是正数,所以pj-pi是负数,因为ti-tj此时已经大于一个正数,则它也一定大于负数,即ti-tj>=pj-pi也成立,即ti+pi>=tj+pj一定成立,同理pi<pj时,ti+pi>=tj+pj,ti-pi>=tj-pj也一定成立。所以满足条件的转移一定满足这两个式子。而满足这两个式子时,ti-tj一定是个正数。所以不用考虑ti的顺序了。

    设val1=ti+pi,val2=ti-pi,则转换为了一个二维偏序问题。一维排序,一维用值域树状数组或者值域线段树优化。【注意】因为t值非常大,需要离散化值域。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #define ll long long
    using namespace std;
    
    int w, n;
    ll val2[100005], pos[100005];
    
    struct node {
        ll val1, val2;
        int t, p, v;
    } pie[100005];
    
    ll TR[400005];
    
    bool cmp ( node a, node b ) {
        return a.val1 < b.val1;
    }
    
    void update ( int nd ) {
        TR[nd] = max ( TR[nd << 1], TR[nd << 1 | 1] );
    }
    
    void insert ( int nd, int l, int r, int pos, ll delta ) {
        if ( l == r ) {
            TR[nd] = delta;
            return ;
        }
        int mid = ( l + r ) >> 1;
        if ( pos <= mid ) insert ( nd << 1, l, mid, pos, delta );
        else insert ( nd << 1 | 1, mid + 1, r, pos, delta );
        update ( nd );
    }
    
    ll query ( int nd, int l, int r, int L, int R ) {
        if ( l >= L && r <= R ) return TR[nd];
        int mid = ( l + r ) >> 1;
        ll ans = 0;
        if ( L <= mid ) ans = max ( ans, query ( nd << 1, l, mid, L, R ) );
        if ( R > mid ) ans = max ( ans, query ( nd << 1 | 1, mid + 1, r, L, R ) );
        return ans;
    }
    
    int main ( ) {
        scanf ( "%d%d", &w, &n );
        for ( int i = 1; i <= n; i ++ ) {
            scanf ( "%d%d%d", &pie[i].t, &pie[i].p, &pie[i].v );
            pie[i].val1 = pie[i].t * 2 + pie[i].p;
            pie[i].val2 = pie[i].t * 2 - pie[i].p;
            val2[i] = pie[i].val2;
        }
        sort ( pie + 1, pie + 1 + n, cmp );
        sort ( val2 + 1, val2 + 1 + n );
        int w = unique ( val2 + 1, val2 + 1 + n ) - val2 - 1;
        for ( int i = 1; i <= n; i ++ ) {
            int pr = lower_bound ( val2 + 1, val2 + 1 + w, pie[i].val2 ) - val2;
            ll tmp = query ( 1, 1, w, 1, pr );
            ll dp = tmp + pie[i].v;
            insert ( 1, 1, w, pr, dp );
        }
        printf ( "%lld", TR[1] );
        return 0;
    }

    10.12更新

    老李布置的练习,又写了一遍....线段树是要取max!!

    #include<bits/stdc++.h>
    #define LL long long
    using namespace std;
    
    struct Node {
        int t, p, v;
        LL v1, v2;
    } pie[100005];
    bool cmp(Node a, Node b) { return a.v1 < b.v1; }
    
    LL TR[400005];
    void update(int nd) {
        TR[nd] = max(TR[nd << 1], TR[nd << 1 | 1]);
    }
    
    void add(int nd, int pos, int l, int r, LL d) {
        if(l == r) {
            TR[nd] = max(TR[nd], d);
            return ;
        }
        int mid = (l + r) >> 1;
        if(pos <= mid)    add(nd << 1, pos, l, mid, d);
        else            add(nd << 1 | 1, pos, mid + 1, r, d);
        update(nd);
    }
    
    LL query(int nd, int L, int R, int l, int r) {
        if(l >= L && r <= R)    return TR[nd];
        int mid = (l + r) >> 1; LL ans = 0;
        if(L <= mid)    ans = max(ans, query(nd << 1, L, R, l, mid));
        if(R > mid)        ans = max(ans, query(nd << 1 | 1, L, R, mid + 1, r));
        return ans;
    }
    
    int w, n;
    LL a[100005];
    int main() {
        scanf("%d%d", &w, &n);
        for(int i = 1; i <= n; i ++) {
            scanf("%d%d%d", &pie[i].t, &pie[i].p, &pie[i].v);
            pie[i].v1 = pie[i].t * 2 + pie[i].p;
            pie[i].v2 = pie[i].t * 2 - pie[i].p;
            a[i] = pie[i].v2;
        }
        sort(pie + 1, pie + 1 + n, cmp);
        sort(a + 1, a + 1 + n);
        int m = unique(a + 1, a + 1 + n) - a - 1;
        for(int i = 1; i <= n; i ++) {
            int pos = lower_bound(a + 1, a + 1 + n, pie[i].v2) - a;
            LL now = query(1, 1, pos, 1, n);
            LL dp = now + pie[i].v;
            add(1, pos, 1, n, dp);
        }
        printf("%lld", TR[1]);
        return 0;
    }
  • 相关阅读:
    android: LayoutInflater使用
    android:ListView bbs Demo
    android:制作 Nine-Patch 图片
    android:单位和尺寸
    android:提升 ListView 的运行效率
    android:定制 ListView 的界面
    android:ListView 的简单用法
    android:创建自定义控件
    android:四种基本布局
    android:ProgressDialog控件
  • 原文地址:https://www.cnblogs.com/wans-caesar-02111007/p/9488610.html
Copyright © 2011-2022 走看看