Live Archive 4327 Parade

来源:互联网 发布:淘宝买家秀在哪里设置 编辑:程序博客网 时间:2024/05/18 03:29

题意:某城由n+1个横向路和m+1个竖向路组成,你的任务是从最南边的路走到最北边的路,使得走过的路上高兴值最大,同一条路不能经过两次,也不能从北向南走,另外,每条横向路有一个长度,在每一行的横向路行走的长度不能超过k

简单起见我们可以看成从北边走到南边

首先预处理数组sum[i][j]表示第i行从第1个点到第j个点的高兴值总和

用f[i][j]表示从i-1行往下走一行位于(i且,j)点时得到的最大的高兴值,我们先不考虑长度的限制,那么容易得到以下方程:

f[i][j]=max{f[i-1][k]+sum[i-1][max(j,k)]-sum[i-1][min(j,k)]}

由于sum[i-1][j]是一个相对常量,所以求f[i-1][k]+sum[i-1][k]的最大值(或求f[i-1][k]-sum[i-1][k]的最大值)要用到单调队列

那么有长度限制该怎么办呢?我们可以再预处理两个数组l[i],r[i]

l[i][j]表示在第i排从第j号点开始向左走能到达的最远的点(即这两个点之间的路的长度和<=k)

那么r[i][j]同理

使用g[j]=f[i-1][k]±sum[i-1][k],然后单调队列里记录编号,如果编号小于l[i][j]或者大于r[i][j]就将队首元素弹出

注意最后答案是max{f[n+2][i]}而不是max{f[n+1][i]}想一想为什么

#include<cstdio>#include<iostream>#include<deque>using namespace std;const int maxn=105,maxm=10005,inf=1e9;inline void _read(int &x){    char t=getchar();bool sign=true;    while(t<'0'||t>'9')    {if(t=='-')sign=false;t=getchar();}    for(x=0;t>='0'&&t<='9';t=getchar())x=x*10+t-'0';    if(!sign)x=-x;}int n,m,k,sum[maxn][maxm],t[maxn][maxm],g[maxm];int f[maxn][maxm],l[maxn][maxm],r[maxn][maxm];deque<int>q;int main(){while(scanf("%d%d%d",&n,&m,&k)&&(n||m||k)){int i,j,x;    for(i=1;i<=n+1;i++)    for(j=1;j<=m;j++){        _read(x);        sum[i][j+1]=sum[i][j]+x;}for(i=1;i<=n+1;i++)    for(j=1;j<=m;j++)_read(t[i][j]);    for(i=1;i<=n+1;i++){    int cur=0,id=1;    l[i][1]=1,r[i][m+1]=m+1;    for(j=2;j<=m+1;j++){    cur+=t[i][j-1];    while(cur>k)cur-=t[i][id++];    l[i][j]=id;}cur=0,id=m;for(j=m;j;j--){cur+=t[i][j];while(cur>k)cur-=t[i][id--];r[i][j]=id+1;}}    for(i=1;i<=m+1;i++)f[n+1][i]=0;    for(i=2;i<=n+2;i++){    while(!q.empty())q.pop_back();    for(j=1;j<=m+1;j++){        g[j]=f[i-1][j]-sum[i-1][j];    while(!q.empty()&&q.front()<l[i-1][j])q.pop_front();    while(!q.empty()&&g[j]>=g[q.back()])q.pop_back();    q.push_back(j);    f[i][j]=max(f[i-1][j],sum[i-1][j]+g[q.front()]);}while(!q.empty())q.pop_back();for(j=m+1;j;j--){g[j]=f[i-1][j]+sum[i-1][j];while(!q.empty()&&q.front()>r[i-1][j])q.pop_front();while(!q.empty()&&g[j]>=g[q.back()])q.pop_back();q.push_back(j);f[i][j]=max(f[i][j],g[q.front()]-sum[i-1][j]);}}int ans=0;for(i=1;i<=m+1;i++)ans=max(ans,f[n+2][i]);    printf("%d\n",ans);}}


0 0
原创粉丝点击