/*
分析:
优先队列+DP。
不科学&&蛋疼、加了一个精心想好的优化结果wa了一下午、去掉就ac了。。。
不过内存占用不算多、648K。
很容易想到dp[i][j]=max(dp[i-1][k]+sum(k~j))(abs(k-j)<=t);由于行的
列j每次改变、每个可进行递推的点k到点j的sum(k~j)都在变化、不好处理;所以改
变下:
假设k<j:
dp[i-1][k]-sum(1~(k-1))+sum(1~j)。
对于每个k点、sum(1~(k-1))固定;对于每个j点、sum(1~j)同样固定;
所以node.val=dp[i-1][k]-sum(1~(k-1)); node.id=k; q.push(node);
维护这个队列既可。
k>j时同理、从右往左进行一个一样的过程既可。
2013-07-16
*/
分析:
优先队列+DP。
不科学&&蛋疼、加了一个精心想好的优化结果wa了一下午、去掉就ac了。。。
不过内存占用不算多、648K。
很容易想到dp[i][j]=max(dp[i-1][k]+sum(k~j))(abs(k-j)<=t);由于行的
列j每次改变、每个可进行递推的点k到点j的sum(k~j)都在变化、不好处理;所以改
变下:
假设k<j:
dp[i-1][k]-sum(1~(k-1))+sum(1~j)。
对于每个k点、sum(1~(k-1))固定;对于每个j点、sum(1~j)同样固定;
所以node.val=dp[i-1][k]-sum(1~(k-1)); node.id=k; q.push(node);
维护这个队列既可。
k>j时同理、从右往左进行一个一样的过程既可。
2013-07-16
*/
#include"iostream"
#include"cstdio"
#include"queue"
#include"cstring"
using namespace std;
const int M=10005;
const int inf=1010000000;
int n,m,x,t;
int dp[2][M],map[M];
struct node{
int id,val;
bool friend operator<(node n1,node n2){
return n1.val<n2.val;
}
};
inline int max(int a,int b){
return a>b?a:b;
}
int main()
{
int i,l;
int now,pre;
int sum_tr,sum_tl;
node head,next;
while(scanf("%d%d%d%d",&n,&m,&x,&t)!=-1)
{
for(i=0;i<2;i++)
for(l=1;l<=m;l++)
dp[i][l]=-inf;
dp[0][x]=0;
for(i=1;i<=n;i++)
{
now=i%2;
pre=1-now;
priority_queue<node>qtl,qtr;
sum_tr=0;
for(l=1;l<=m;l++)
{
scanf("%d",&map[l]);
sum_tr+=map[l];
if(dp[pre][l]!=-inf)
{
next.id=l;
next.val=dp[pre][l]-sum_tr+map[l];
qtr.push(next);
}
while(!qtr.empty())
{
head=qtr.top();
if(head.id<l-t) {qtr.pop();continue;}
dp[now][l]=head.val+sum_tr;
break;
}
}
sum_tl=0;
for(l=m;l>=1;l--)
{
sum_tl+=map[l];
if(dp[pre][l]!=-inf)
{
next.id=l;
next.val=dp[pre][l]-sum_tl+map[l];
qtl.push(next);
}
while(!qtl.empty())
{
head=qtl.top();
if(head.id>l+t) {qtl.pop();continue;}
dp[now][l]=max(dp[now][l],head.val+sum_tl);
break;
}
}
}
int ans=-inf;
now=n%2;
for(l=1;l<=m;l++) if(ans<dp[now][l]) ans=dp[now][l];
cout<<ans<<endl;
}
return 0;
}