题目描述
题解
首先预处理出val[t][loc]表示时刻t赶到loc的位置能收获的价值。
设f(i,j)表示第i时刻走到j位置是的最大收获。那么f(i,j)=max{f(i-1,j-2),f(i-1,j-1),f(i-1,j),f(i-1,j+1),f(i-1,j+2)}.
但是输出方案比较麻烦,可以记一个pre然后每一次递归统计。需要注意的是每一次更新f值的时候都要比较字典序再判断是否更新,不能光考虑最后一步。
代码
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define N 1005
int w,h,a,b,c,d,p,Max,ans;
int val[N][N],f[N][N],pre[N][N];
struct hp{int a[N];}anso,order;
void find(int i,int j)
{
if (!i||!j) return;
find(i-1,j+pre[i][j]);
order.a[++order.a[0]]=-pre[i][j];
}
bool compare(hp a,hp b)
{
if (!a.a[0]) return true;
for (int i=1;i<=Max;++i)
{
if (a.a[i]>b.a[i]) return true;
if (a.a[i]<b.a[i]) return false;
}
return false;
}
int main()
{
freopen("freepizza.in","r",stdin);
freopen("freepizza.out","w",stdout);
scanf("%d%d",&w,&h);
while (~scanf("%d%d%d%d",&a,&b,&c,&d))
{
if ((h-1)%c==0)
{
int t=a+(h-1)/c;Max=max(Max,t);
val[t][b]+=d;
}
p++;
}
memset(f,128,sizeof(f));
f[0][w/2+1]=val[0][w/2+1];
if (!p)
{
puts("0");
return 0;
}
if (Max==0)
{
printf("%d\n",f[0][w/2+1]);
puts("0");
return 0;
}
for (int i=1;i<=Max;++i)
for (int j=1;j<=w;++j)
{
f[i][j]=f[i-1][j];
pre[i][j]=0;
if (j+2<=w)
{
if (f[i][j]<f[i-1][j+2])
{
f[i][j]=f[i-1][j+2];
pre[i][j]=2;
}
else if (f[i][j]==f[i-1][j+2])
{
order.a[0]=0;
find(i,j);anso=order;
order.a[0]=0;
find(i-1,j+2);order.a[++order.a[0]]=-2;
if (compare(anso,order))
{
f[i][j]=f[i-1][j+2];
pre[i][j]=2;
}
}
}
if (j+1<=w)
{
if (f[i][j]<f[i-1][j+1])
{
f[i][j]=f[i-1][j+1];
pre[i][j]=1;
}
else if (f[i][j]==f[i-1][j+1])
{
order.a[0]=0;
find(i,j);anso=order;
order.a[0]=0;
find(i-1,j+1);order.a[++order.a[0]]=-1;
if (compare(anso,order))
{
f[i][j]=f[i-1][j+1];
pre[i][j]=1;
}
}
}
if (j-1>=1)
{
if (f[i][j]<f[i-1][j-1])
{
f[i][j]=f[i-1][j-1];
pre[i][j]=-1;
}
else if (f[i][j]==f[i-1][j-1])
{
order.a[0]=0;
find(i,j);anso=order;
order.a[0]=0;
find(i-1,j-1);order.a[++order.a[0]]=1;
if (compare(anso,order))
{
f[i][j]=f[i-1][j-1];
pre[i][j]=-1;
}
}
}
if (j-2>=1)
{
if (f[i][j]<f[i-1][j-2])
{
f[i][j]=f[i-1][j-2];
pre[i][j]=-2;
}
else if (f[i][j]==f[i-1][j-2])
{
order.a[0]=0;
find(i,j);anso=order;
order.a[0]=0;
find(i-1,j-2);order.a[++order.a[0]]=2;
if (compare(anso,order))
{
f[i][j]=f[i-1][j-2];
pre[i][j]=-2;
}
}
}
f[i][j]+=val[i][j];
}
for (int i=1;i<=w;++i)
if (ans<f[Max][i])
{
ans=f[Max][i];
order.a[0]=0;
find(Max,i);
anso=order;
}
else if (ans==f[Max][i])
{
order.a[0]=0;
find(Max,i);
if (compare(order,anso)) anso=order;
}
printf("%d\n",ans);
for (int i=1;i<=anso.a[0];++i)
printf("%d\n",anso.a[i]);
}
总结
①记录方案的时候要注意每一次更新f值都要判断。