hdu 4374 (单调队列+dp)

d[i][j]表示i行j列格子可以得到的最大值

顺着来的时候

d[i][j]=max(d[i-1][k]+sum[k...j])=max(d[i-1][k]-sum[1..k-1]+sum[1...j])  sum[1...j]是固定值 只要找d[i-1][k]+sum[1...k]  的最大值就可以了

找法就是维护一个单调递减的队列,每次加入一个值进去就把队列值后面小于它的点都删掉,把前面j-k>t的点删掉(走的步数大于t步),d[i][j]=队首值+sum[1...j]

逆着来的时候

d[i][j]=max(d[i-1][k]+sum[k...j])=max(d[i-1][k]+sum[1...k])-sum[1...j-1]  sum[1...k]是固定值 只要找d[i-1][k]-sum[1...j]  的最大值就可以了

维护一个单调递减的队列,每次加入一个值进去就把队列值后面小于它的点都删掉,把前面j-k>t的点删掉(走的步数大于t步),d[i][j]=队首值-sum[1...k]

 1 #include<iostream>
 2 #include<string.h>
 3 #include<stdio.h>
 4 #include<queue>
 5 using namespace std;
 6 #define INF -9999999
 7 int a[102][10002],d[102][10002],sum[102][10002];
 8
 9 struct node
10 {
11     int zhi,wei;
12 } q[10002];
13
14
15 int main()
16 {
17     int k,n,m,x,t;
18     while(~scanf("%d%d%d%d",&n,&m,&x,&t))
19     {
20         for(int i=1; i<=n; i++)
21             for(int j=1; j<=m; j++)
22                 scanf("%d",&a[i][j]);
23         for(int i=1; i<=n; i++)
24             for(int j=1; j<=m; j++)
25                 d[i][j]=INF;
26         memset(sum,0,sizeof(sum));
27         d[1][x]=a[1][x];
28         for(int i=1; i<=t&&i+x<=m; i++)
29             d[1][i+x]=max(d[1][x+i],d[1][x+i-1]+a[1][x+i]);
30
31         for(int i=1; i<=t&&x-i>=1; i++)
32             d[1][x-i]=max(d[1][x-i],d[1][x-i+1]+a[1][x-i]);
33
34         for(int i=2; i<=n; i++)
35         {
36             for(int j=1; j<=m; j++)
37                 sum[i][j]=sum[i][j-1]+a[i][j];
38
39             int front1=0,rear=0;
40             for(int j=1; j<=m; j++)
41             {
42
43                 int temp=d[i-1][j]-sum[i][j-1];
44                 while(front1<rear&&q[rear-1].zhi<temp)
45                     rear--;
46                 q[rear].zhi=temp;
47                 q[rear++].wei=j;
48
49                 while(front1<rear&&j-q[front1].wei>t)
50                     front1++;
51
52                 d[i][j]=max(d[i][j],q[front1].zhi+sum[i][j]);
53
54             }
55             front1=0,rear=0;
56             for(int j=m; j>=1; j--)
57             {
58                 int temp=d[i-1][j]+sum[i][j];
59                 while(q[rear-1].zhi<temp&&front1<rear)
60                     rear--;
61                 q[rear].zhi=temp;
62                 q[rear++].wei=j;
63
64                 while(front1<rear&&q[front1].wei-j>t)
65                     front1++;
66                 d[i][j]=max(d[i][j],q[front1].zhi-sum[i][j-1]);
67             }
68
69         }
70         int ans=0;
71         for(int j=0; j<=n; j++)
72             for(int i=1; i<=m; i++)
73                 ans=max(d[n][i],ans);
74
75         printf("%d\n",ans);
76     }
77     return 0;
78 }
时间: 2024-10-26 20:20:11

hdu 4374 (单调队列+dp)的相关文章

hdu 4374 单调队列

求最大不超过k的连续子序列的和   单调队列 #include<stdio.h> #include<string.h> #include<iostream> using namespace std; int num[201000],id[201000],sum[201000]; int main() { int n,m,i,j,T; scanf("%d",&T); while(T--) { scanf("%d%d",&am

hdu4374单调队列+dp

http://acm.hdu.edu.cn/showproblem.php?pid=4374 Problem Description Now there is a game called the new man down 100th floor. The rules of this game is: 1.  At first you are at the 1st floor. And the floor moves up. Of course you can choose which part

HDU 3507 单调队列 斜率优化

斜率优化的模板题 给出n个数以及M,你可以将这些数划分成几个区间,每个区间的值是里面数的和的平方+M,问所有区间值总和最小是多少. 如果不考虑平方,那么我们显然可以使用队列维护单调性,优化DP的线性方法来做,但是该题要求的是区间和的平方,于是要转换单调的计算方法为斜率,也就是凸线. 其他就是最基本的单调DP /** @Date : 2017-09-04 15:39:05 * @FileName: HDU 3507 单调队列 斜率优化 DP.cpp * @Platform: Windows * @

POJ 3017 单调队列dp

Cut the Sequence Time Limit: 2000MS   Memory Limit: 131072K Total Submissions: 8764   Accepted: 2576 Description Given an integer sequence { an } of length N, you are to cut the sequence into several parts every one of which is a consecutive subseque

HDU 3530 单调队列

Subsequence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 3995    Accepted Submission(s): 1308 Problem Description There is a sequence of integers. Your task is to find the longest subsequenc

[TyvjP1313] [NOIP2010初赛]烽火传递(单调队列 + DP)

传送门 就是个单调队列+DP嘛. ——代码 1 #include <cstdio> 2 3 const int MAXN = 1000001; 4 int n, m, h = 1, t = 1, ans = ~(1 << 31); 5 int q[MAXN], a[MAXN], f[MAXN]; 6 7 inline int min(int x, int y) 8 { 9 return x < y ? x : y; 10 } 11 12 int main() 13 { 14

hdu 3401(单调队列优化dp)

注意:这题题意是有操作的天数相隔要大于w 然后列出状态转移方程就可以发现,可以用优点队列优化啦. 构造状态dp[i][j]表示第i 天拥有 j只股票的时候,赚了多少钱 状态转移有: 1.从前一天不买不卖: dp[i][j]=max(dp[i-1][j],dp[i][j]) 2.从前i-W-1天买进一些股: dp[i][j]=max(dp[i-W-1][k]-(j-k)*AP[i],dp[i][j]) 3.从i-W-1天卖掉一些股: dp[i][j]=max(dp[i-W-1][k]+(k-j)*

hdu 3401 单调队列优化+dp

http://acm.hdu.edu.cn/showproblem.php?pid=3401 Trade Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 5188    Accepted Submission(s): 1776 Problem Description Recently, lxhgww is addicted to stoc

HDU 5945 维护一个单调队列 dp

Fxx and game Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)Total Submission(s): 688    Accepted Submission(s): 162 Problem Description Young theoretical computer scientist Fxx designed a game for his students. In

UVA Live Achrive 4327 Parade (单调队列,dp)

容易想到dp[i][j]表示在第i行j个路口的开始走最大高兴值. 每次可以向左走,或者向右边走,然后向北走.(或者直接往北) 向左走到,状态转移为dp[i][j] = dp[i][k] + happy[i][k][j](为了方便处理,i从1开始编号,0行dp值存0) 处理出前缀和,happy[i][k][j]表示为sum[i][j] - sum[i][k] 向左走应该取max(dp[i][k]-sum[i][k]) k应该满足time[i][k][j] <= k 随着j的变化k的范围是一个滑动窗