您的位置:首页 > 运维架构

hdu4374 One hundred layer(单调队列维护dp)

2017-10-25 19:26 489 查看

题面

题意

给出宽n,长m的矩阵,你一开始在第一行第k个,在每行你最多向左或向右移动t步(在底层和顶层皆可移动),移动后进入下一层,问到达底层后的最大分数是多少.

方法

用dp思想可知,只需要知道到达每一点的最大得分是多少,若穷举每行的起点和终点进行状态转移,复杂度为O(n*m^2)必然TLE.

其实在第i行若终点为j,则起点必然在max(1,j-t)与min(m,j+t)之间,对于此类求区间最大值的题目当用单调队列来维护,则复杂度为O(n*m).

也可以这么想:

不难得到状态转移方程:

在第i行中,k为起点,j为终点,qz表示前缀和

j>=k时

dp[i][j]=dp[i-1][k]+qz[i][j]-qz[i][k-1] ->

dp[i][j]-qz[i][j]=dp[i-1][k]-qz[i][k-1]

j<=k时

dp[i][j]=dp[i-1][k]+qz[i][k]-qz[i][j-1]->

dp[i][j]+qz[i][j-1]=dp[i-1][k]+qz[i][k]

因而只需用单调队列求出等号右边的最小值

代码

#include<bits/stdc++.h>
#define ll long long
#define M 110
#define N 10100
#define MN -100000000
using namespace std;

ll m,n,k,l,num[M][N],qz[M][N],last[N],now,dp[M][N],ans;
struct Dq
{
ll nu
,id
,head,tail,len;
void init()
{
head=1;
tail=0;
}
void push(ll u,ll v)
{
if(head<=tail&&v-id[head]>=len) head++;
while(head<=tail&&u>=nu[tail]) tail--;
tail++;
nu[tail]=u;
id[tail]=v;
}
ll front()
{
return nu[head];
}
ll front2()
{
return id[head];
}
void pop()
{
head++;
}
bool empty()
{
if(head>tail) return 1;
return 0;
}
void getlen(ll u)
{
len=u;
}
void print()
{
ll i;
for(i=head;i<=tail;i++)
{
cout<<nu[i]<<" ";
}
cout<<endl;
}
void print2()
{
ll i;
cout<<head<<" "<<tail<<endl;
for(i=head;i<=tail;i++)
{
cout<<nu[i]<<" ";
}
cout<<endl;
}
};
Dq dq;

int main()
{
ll i,j;
while(~scanf("%lld%lld%lld%lld",&m,&n,&k,&l))
{
dq.getlen(l+1);
for(i=1;i<=m;i++)
{
for(j=1;j<=n;j++)
{
scanf("%lld",&num[i][j]);
}
}
for(i=1;i<=m;i++)
{
qz[i][1]=num[i][1];
for(j=2;j<=n;j++)
{
qz[i][j]=qz[i][j-1]+num[i][j];
}
}
for(i=1;i<=n;i++) dp[1][i]=MN;
dp[1][k]=num[1][k];
for(i=k+1;i<=min(k+l,n);i++) dp[1][i]=dp[1][i-1]+num[1][i];
for(i=k-1;i>=max((ll)1,k-l);i--) dp[1][i]=dp[1][i+1]+num[1][i];
for(i=2;i<=m;i++)
{
//left
dq.init();
for(j=1;j<=n;j++)
{
dq.push(dp[i-1][j]+qz[i][j],j);
if(j>l) dp[i][j-l]=dq.front()-qz[i][j-l-1];
}
for(j=1;j<=min(l,n);j++)
{
while(!dq.empty()&&dq.front2()<n-l+j) dq.pop();
dp[i][n-l+j]=dq.front()-qz[i][n-l+j-1];
}
//right
dq.init();
for(j=n;j>=1;j--)
{
dq.push(dp[i-1][j]-qz[i][j-1],n-j+1);
if(j<=n-l) dp[i][j+l]=max(dp[i][j+l],dq.front()+qz[i][j+l]);
}
for(j=1;j<=l;j++)
{
while(!dq.empty()&&n-dq.front2()+1>l-j+1) dq.pop();
dp[i][l-j+1]=max(dp[i][l-j+1],dq.front()+qz[i][l-j+1]);
}
}
ans=MN;
for(i=1;i<=n;i++)
{
ans=max(ans,dp[m][i]);
}
printf("%lld\n",ans);
}
}

/*
right :
dp[i][j]=dp[i-1][k]+qz[i][j]-qz[i][k-1]
dp[i][j]-qz[i][j]=dp[i-1][k]-qz[i][k-1]
left :
dp[i][j]=dp[i-1][k]+qz[i][k]-qz[i][j-1]
dp[i][j]+qz[i][j-1]=dp[i-1][k]+qz[i][k]
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: