zoukankan      html  css  js  c++  java
  • 【USACO OPEN 10】hop

    奶牛们正在回味童年,玩一个类似跳格子的游戏,在这个游戏里,奶牛们在草地上画了一行N个格子,(3 <=N <= 250,000),编号为1..N。

    ::点击图片在新窗口中打开::
      就像任何一个好游戏一样,这样的跳格子游戏也有奖励!第i个格子标有一个数字V_i(-2,000,000,000 <=V_i <= 2,000,000,000)表示这个格子的钱。奶牛们想看看最后谁能得到最多的钱。
      
    规则很简单:
      * 每个奶牛从0号格子出发。(0号格子在1号之前,那里没钱)  *她向N号格子进行一系列的跳跃(也可以不跳),每次她跳到的格子最多可以和前一个落脚的格子差K格(1 <= K <= N)(比方说,当前在1号格,K=2, 可以跳到2号和3号格子)
      *在任何时候,她都可以选择回头往0号格子跳,直到跳到0号格子。另外,除了以上规则之外,
       回头跳的时候还有两条规则:    
        *不可以跳到之前停留的格子。
        *除了0号格子之外,她在回来的时候,停留的格子必须是恰巧过去的时候停留的某个格子的前一格(当然,也可以跳过某些过去时候停留的格子)。简单点说,如果i号格子是回来 停留的格子,i+1号就必须是过去停留的格子,如果i+1号格子是过去停留的格子,i号格子 不一定要是回来停留的格子。(如果这里不太清楚的可以去看英文原文)

      她得到的钱就是所有停留过的格子中的数字的和,请你求出最多奶牛可以得到的钱数。

      在样例中,K=2,一行5个格子。  
      
      ::点击图片在新窗口中打开::
      
      一个合法的序列Bessie可以选择的是0[0], 1[0], 3[2], 2[1], 0[0]。(括号里的数表示钱数)
    这样,可以得到的钱数为0+0+2+1+0 = 3。

      如果Bessie选择一个序列开头为0, 1, 2, 3, ...,那么她就没办法跳回去了,因为她没办法再跳到一个之前没跳过的格子。
      序列0[0], 2[1], 4[-3], 5[4], 3[2], 1[0], 0[0]是最大化钱数的序列之一,最后的钱数为(0+1-3+4+2+0 = 4).

    思考过程:这道题很奇怪的有两个过程,第一个过程是去的过程,第二个过程是回来的过程,而且回来时候经过的每个格子都是去时格子的前驱;

    我先考虑的是设f[i]表示去时到达的最右边的格子是i时的最大得分,但是尝试之后发现这是无法转移的,因为我不知道回来的时候会不会经过它前面的那个格子,经过不经过两种情况都需要考虑,再加上每次最多跳k个格子这样的限制,设f[i]这样的状态很显然是不可做的;

    到这里就有点进了死胡同的感觉,于是去看了下题解,然后回来继续做。。。

    看完了题解就感觉豁然开朗了,我们可以设f[i]表示回来时第i个格子是第一个跳的格子的可得到的最大得分;这么设置,一是当前状态对以后状态没有了后效性,二是便于优化;

    想这道题时候其实隐隐约约把握到了这道题需要从后往前想的思路,但是没有付诸实际,所以最后只好去看题解;

    代码上有些细节需要注意;

    代码:

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<cstdlib>
     5 #include<algorithm>
     6 #include<iomanip>
     7 #include<map>
     8 #include<set>
     9 #include<vector>
    10 #include<ctime>
    11 #include<cmath>
    12 #define LL long long 
    13 using namespace std;
    14 #define LL long long 
    15 #define up(i,j,n) for(int i=(j);(i)<=(n);(i)++)
    16 const int maxn=502000;
    17 int n,k;
    18 int a[maxn];
    19 LL f[maxn],sum[maxn];
    20 int q[maxn],head=1,tail=1,g[maxn];
    21 void print(LL x){printf("%I64d
    ",x);exit(0);}
    22 inline LL max(LL x,LL y){return x>y?x:y;}
    23 inline LL min(LL x,LL y){return x>y?y:x;}
    24 int main(){
    25     scanf("%d%d",&n,&k);n++;
    26     up(i,2,n){scanf("%d",&a[i]);sum[i]=sum[i-1]+max(0,a[i]);}
    27     if(k==1)print(max(a[1],0));
    28     LL ans=0;
    29     for(int i=n+1;i<=n+k;i++)sum[i]=sum[i-1];
    30     up(i,1,n){
    31         while(i-q[head]>k&&head<=tail)head++;
    32         f[i]=f[q[head]]-sum[q[head]+1]+sum[i-1]+a[i]+a[i+1];
    33         while(f[q[tail]]-sum[q[tail]+1]<=f[i-1]-sum[i]&&tail>=head)tail--;
    34         q[++tail]=i-1;f[1]=max(0LL,f[1]);
    35         ans=max(ans,f[i]+sum[i+k]-sum[i+1]);
    36     }
    37     print(ans);
    38     return 0;
    39 }
    View Code
  • 相关阅读:
    Getting started with the Web ADF
    将搜狗浏览器设置为IIS的默认浏览器
    What is installed with the Web ADF?
    如何修改Flex的默认浏览器
    What is the Web Application Developer Framework
    windows C++获得本地IP地址
    lua table函数库
    【铸铁】C++服务器面试题.doc
    VC2008下提示找不到MSVCP90D.dll的解决办法
    排序
  • 原文地址:https://www.cnblogs.com/chadinblog/p/5935022.html
Copyright © 2011-2022 走看看