hdu 4374 One hundred layer (dp +单调队列 2012 Multi-University Training Contest 8 )

acm.hdu.edu.cn/showproblem.php?pid=4374

 

题意: 有n层,每层有m个part。在一层中你只能向着一个方向移动(左或者右),最多能移动T步,

      经过每个部分是都能得到这个部分的分数。起始位置在x位置,从第一层到最顶层能得到最多的分数

题解:

dp + 单调队列 ;

对于 左边我们可以得到  dp[i][j] = max( dp[i - 1][k]  + sum(k, j))       j - t <=k <= j;

我们的队列 要维护的 就是 

dp[i - 1][k]  + sum(k, j)
 由于 sum (k ,j) 单调队列要维护的状态必须是和 现在的状态 无关(或着说是 以知的),但 sum(k,j)  用到了现在的状态;

 

所以 我们要进行转换一下,   sum(k,j) = sum (1,j) - sum (1,k - 1);

所以 原式变为    

dp[i - 1][k]  + sum (1,j) - sum (1,k - 1)   = (dp[i - 1][k]   - sum(1,k)) + sum (1,j) 
而 dp[i -1][k] - sum(1,k - 1)  相对于 dp[i][j]  来说 是 以知的   所以    
dp[i -1][k] - sum(1,k - 1)      就是  我们 队列 要维护的状态

 

右边同理 可得

 

 

  1 #include<stdio.h>
  2 #include<iostream>
  3 #include<algorithm>
  4 #include<cstring>
  5 #include<cmath>
  6 #include<queue>
  7 #include< set>
  8 #include<list>
  9 #include<map>
 10  #define Min(a,b)  a>b?b:a
 11  #define Max(a,b)  a>b?a:b
 12  #define CL(a,num)  memset(a,num,sizeof(a));
 13  #define inf 99999999
 14  #define maxn    10010
 15  #define mod 100000007
 16  #define eps  1e-6
 17  #define ll  long long
 18  #define M   15520
 19  using  namespace std;
 20  int n,m,x,t;
 21  struct node
 22 {
 23      int x;
 24      int w;
 25     node( int xx, int yy): x(xx),w(yy){}
 26 };
 27  int f[ 110][maxn],sum[maxn] ,dp[ 110][maxn];
 28  int main()
 29 {
 30      // freopen("data.txt","r",stdin);
 31       int i ,j ;
 32      while(scanf( " %d%d%d%d ",&n,&m,&x,&t)!=EOF)
 33     {
 34         list<node>que;
 35          for(i =  0; i < n ;++i)
 36         {
 37              for(j =  1 ;j <= m; ++j)
 38             scanf( " %d ",&f[i][j]);
 39         }
 40 
 41          for(i =  0; i <= n;++i)
 42         {
 43              for( j =  0; j <= m ;++j)
 44             {
 45                 dp[i][j] = -inf ;
 46             }
 47         }
 48           int cnt = f[ 0][x];
 49          dp[ 0][x] = f[ 0][x] ;
 50          for(i =  0,j = x -  1; i < t&& j >= 1;i++,j--) // 往左处理
 51          {   cnt += f[ 0][j];
 52             dp[ 0][j] = cnt ;
 53         }
 54 
 55         cnt = f[ 0][x] ;
 56          for(i =  0,j = x +  1; i < t && j <= m;i++,j++)// 往右处理
 57         {
 58            cnt += f[ 0][j] ;
 59            dp[ 0][j] = cnt ;
 60 
 61 
 62         }
 63 
 64          for(i =  1; i < n;++i)
 65         {
 66             sum[ 0] =  0;
 67             que.clear() ; //   注意要清空  我就 WA 一次
 68               for(j =  1 ; j <= m ;++j)//左处理
 69             {
 70 
 71 
 72 
 73                 sum[j] = sum[j -  1] + f[i][j] ;
 74 
 75                  while(!que.empty() && que.front().x < j - t)   //距离 大于 t 了 要出队列
 76                    que.pop_front();
 77 
 78                     int  tmp = dp[i -  1][j] - sum[j -  1] ;
 79 
 80                  while(!que.empty() && que.back().w  <= tmp)
 81                      que.pop_back() ;
 82 
 83                  que.push_back(node(j,tmp));
 84                  if(!que.empty())
 85                     dp[i][j] =  sum[j] + que.front().w  ;
 86 
 87             }
 88 
 89 
 90 
 91 
 92 
 93             que.clear() ;
 94             sum[m +  1] =  0;
 95              for(j = m ; j >=  1 ;--j)//  右处理
 96             {
 97 
 98 
 99                 sum[j] = sum[j +  1] + f[i][j] ;
100 
101                  while(!que.empty() && que.front().x - j  > t)//距离 大于 t 了 要出队列
102                    que.pop_front();
103 
104                     int  tmp = dp[i -  1][j] - sum[j +  1] ;
105 
106                  while(!que.empty() && que.back().w  <= tmp)
107                      que.pop_back() ;
108 
109                  que.push_back(node(j,tmp));
110 
111                  if(!que.empty())
112                     dp[i][j] = max(dp[i][j],sum[j] + que.front().w );
113                     
114             }
115 
116 
117      }
118 
119         int ans = dp[n -  1][ 1];
120          for(i =  2;i <= m;++i)
121         {
122             ans = max(ans,dp[n -  1][i]);
123         }
124         printf( " %d\n ",ans);
125 
126 
127 
128     }
129 }

 

 

 

 

 

 

   

 

 

 

 

 

 

转载于:https://www.cnblogs.com/acSzz/archive/2012/08/17/2644370.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值