zoukankan      html  css  js  c++  java
  • P3089 [USACO13NOV]POGO的牛Pogo-Cow

    P3089 [USACO13NOV]POGO的牛Pogo-Cow

    FJ给奶牛贝西的脚安装上了弹簧,使它可以在农场里快速地跳跃,但是它还没有学会如何降低速度。

    FJ觉得让贝西在一条直线的一维线路上进行练习,他在不同的目标点放置了N (1 <= N <= 1000)个目标点,目标点i在目标点x(i),该点得分为p(i)。贝西开始时可以选择站在一个目标点上,只允许朝一个方向跳跃,从一目标点跳到另外一个目标点,每次跳跃的距离大于等于上一次跳跃的距离相等,并且必须跳到一个目标点。

    每跳到一个目标点,贝西可以拿到该点的得分,请计算他的最大可能得分。

    Solution

    这题日了我好久啊
    刚开始推了一下以为是单调队列
    后面发现有个点(没打草稿脑算)推错了。。

    (dp[i][j]) 为跳到第 (i) 个点, 从 (j) 点跳过来的最大价值
    那么容易想到如下转移: $$dp[i][j] = max_{dis(i, j) geq dis(j, k)}dp[j][k] + v[i]$$
    其复杂度为 (O(n^{3})), 难以接受
    考虑优化, 能不能省掉某一维枚举
    当然从可行性入手, 观察如下式子: $$dis(i, j) geq dis(j, k)$$
    对于一个特定的 (j) , 我们将其dp数组全部列出 $$dp[j][1], dp[j][2], dp[j][3],...,dp[j][j]$$
    排除 (i) 的影响, 我们先把式子写成 (dis(j, k) leq t) $$abs(p_{j} - p_{k}) leq t$$
    (i, j) 不变, 观察 (k) 对不等式成立的影响, 发现当 (k) 越小, 不等式越有可能成立
    也就是说, 存在一个位置 (x) , 满足:$$abs(p_{j} - p_{x}) leq t$$ $$abs(p_{j} - p_{x - 1}) > t$$
    ([x, j]) 范围内 (dp[j][k]) 全部可取, ([1, x - 1]) 范围内 (dp[j][k]) 全部不可取
    对于特定的 (j)(t) 随着 (i) 的增大而增大, 所以 (x)(i) 的增大而减小
    于是对于每个 (j) 维护一个位置 (x), 记为 (head[j]) 表示其右端全部可取
    同时维护可取的部分的最大值即可

    Code

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<cstring>
    #include<algorithm>
    #include<climits>
    #define LL long long
    #define REP(i, x, y) for(int i = (x);i <= (y);i++)
    using namespace std;
    int RD(){
        int out = 0,flag = 1;char c = getchar();
        while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
        while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
        return flag * out;
        }
    const int maxn = 2019;
    int num, ans;
    struct Point{int p, v;}p[maxn];
    int dp[maxn][maxn];//跳到i,从j跳过来的最大得分
    bool cmp1(Point a, Point b){return a.p < b.p;}
    bool cmp2(Point a, Point b){return a.p > b.p;}
    void init(){
    	num = RD();
    	REP(i, 1, num)p[i] = (Point){RD(), RD()};
    	}
    int head[maxn];//目前合法的第一个dp[i][x]位置
    int maxx[maxn];//目前最大的关于i的上一项
    void DP(){
    	memset(dp, 0, sizeof(dp));
    	REP(i, 1, num)dp[i][i] = maxx[i] = p[i].v, head[i] = i;//作为起点
    	REP(i, 1, num){
    		REP(j, 1, i - 1){
    			dp[i][j] = maxx[j] + p[i].v;
    			ans = max(ans, dp[i][j]);
    			}
    		REP(j, 1, i){
    			while(head[j] > 1 && (abs(p[i + 1].p - p[j].p) >= abs(p[j].p - p[head[j] - 1].p))){
    				head[j]--;
    				maxx[j] = max(maxx[j], dp[j][head[j]]);
    				}
    			}
    		}
    	}
    void solve(){
    	sort(p + 1, p + 1 + num, cmp1);//顺着排序
    	DP();
    	sort(p + 1, p + 1 + num, cmp2);//倒着排序
    	DP();
    	printf("%d
    ", ans);
    	}
    int main(){
    	init();
    	solve();
    	return 0;
    	}
    
  • 相关阅读:
    菜根谭#188
    菜根谭#187
    Single value range only allowed in SystemVerilog
    LUTs, Flip-Flop, Slice
    FPGA 的 RAM 的 区别
    GPU core clock, shader clock ???
    更改Mac的Terminal 格式
    GPU share memory 的应用 (主要内容转载)
    Mac text edit & pdf reader
    Programming Font
  • 原文地址:https://www.cnblogs.com/Tony-Double-Sky/p/9885469.html
Copyright © 2011-2022 走看看