题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=116242#problem/E
题意:差不多就是男人勇下百层的游戏。从第一层到最后一层最多能够拿到多少分数。每层里面最多可以左右平移T个单位,同时从那个地方到下一层。一开始在第一层的X处。
首先要了解什么是单调队列,这里推荐一个博客写的很不错,直接引用了:http://blog.csdn.net/justmeh/article/details/5844650
用dp(i,j)表示在第i层的第j个位置所能得到的最多的分数,然后这题就可以在每一层用单调队列进行双向维护dp(i,j)的值了。
具体见代码:
1 #include <stdio.h> 2 #include <algorithm> 3 #include <string.h> 4 #include <queue> 5 using namespace std; 6 7 int dp[100+5][10000+5]; 8 int num[100+5][10000+5]; 9 int n,m,x,t; 10 11 struct node 12 { 13 int id,val; 14 node (int id=0,int val=0):id(id),val(val){} 15 }; 16 void solve() 17 { 18 for(int i=0;i<=10000+4;i++) dp[0][i]=-0x3f3f3f3f; 19 dp[0][x]=0; 20 for(int i=1;i<=n;i++) 21 { 22 deque<node> Q; 23 for(int j=1;j<=m;j++) 24 { 25 int tem=dp[i-1][j]-num[i][j-1]; //从j出开始计算和的话,是减掉其前一个的 26 while(!Q.empty()&&tem>Q.back().val) Q.pop_back(); 27 Q.push_back(node(j,tem)); 28 while(!Q.empty()&&j-Q.front().id>t) Q.pop_front(); 29 dp[i][j]=Q.front().val+num[i][j]; 30 } 31 while(!Q.empty()) Q.pop_back(); 32 for(int j=m;j>=1;j--) 33 { 34 int tem=dp[i-1][j]+num[i][j]; //逆向维护和正向的次序相反 35 while(!Q.empty()&&tem>Q.back().val) Q.pop_back(); 36 Q.push_back(node(j,tem)); 37 while(!Q.empty()&&Q.front().id-j>t) Q.pop_front(); 38 dp[i][j]=max(dp[i][j],Q.front().val-num[i][j-1]); 39 } 40 } 41 int ans=dp[n][1]; 42 for(int i=2;i<=m;i++) ans=max(ans,dp[n][i]); 43 printf("%d ",ans); 44 } 45 46 int main() 47 { 48 while(scanf("%d%d%d%d",&n,&m,&x,&t)==4) 49 { 50 for(int i=1;i<=n;i++) 51 for(int j=1;j<=m;j++) 52 { 53 scanf("%d",&num[i][j]); 54 num[i][j]+=num[i][j-1]; 55 } 56 solve(); 57 } 58 return 0; 59 }
思路倒是简单,但是被莫名其妙的坑了很久。。因为对于上面结构体里面的构造方法,写(node)(j,tem)是错误的!正确写法是node(j,tem)。因为以前使用{node}(j,tem)的写法有时候会CE,所以换了这种写法,找了很长时间的错误。。另外,在下面用tem变量时一开始用的是t,忘记和全局变量的t重复了。。悲剧啊QAQ。。。