hdu 4374 One hundred layer (dp +单调队列 2012 MultiUniversity 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/p/2644370.html