记录编号 |
320285 |
评测结果 |
AAAAAA |
题目名称 |
[NOI 1998]免费馅饼 |
最终得分 |
100 |
用户昵称 |
Go灬Fire |
是否通过 |
通过 |
代码语言 |
C++ |
运行时间 |
0.017 s |
提交时间 |
2016-10-11 20:32:20 |
内存使用 |
11.99 MiB |
显示代码纯文本
/*
Name: 免费馅饼
Copyright:
Author: Go灬Fire
Date: 11/10/16 20:25
Description: c[i][j]代表时间为i时在j处馅饼的价值,f[i][j]代表时间为i时在j处已获得的最优的解
首先要处理根本不可能接到的馅饼,去掉
Dp是s数组要记录它是从哪一个状态转移
递归输出
特判:舞台宽度为1,站着不动吃馅饼
*/
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<iostream>
#define Begin freopen("freepizza.in","r",stdin);freopen("freepizza.out","w",stdout);
#define End fclose(stdin);fclose(stdout);
using namespace std;
const int maxn=1010;
int w,h,f[maxn][maxn],c[maxn][maxn],s[maxn][maxn];
void Init();
void Print(int t,int w){
if(t<=0 || w<=0) return;
Print(t-1,w+s[t][w]);
printf("%d\n",-s[t][w]);
}
int _max(int a,int b,int c,int d,int e){
a=max(a,b);c=max(c,d);c=max(c,e);
return max(a,c);
}
int main(){
Begin;
Init();
//system("pause");
End;
return 0;
}
void Init(){
//f[i][j]与c[i][j]第一维是时间,第二维是空间
scanf("%d%d",&w,&h);
int time=0,end=0,x,sp,val;
while(scanf("%d%d%d%d",&time,&x,&sp,&val)!=EOF){
if((h-1)%sp!=0)continue;//根本不可能接到的馅饼
c[time+(h-1)/sp][x]+=val;
end=max(end,time+(h-1)/sp);
}
if(w==1){
int ans=0;
for(int i=1;i<=end;i++)ans+=c[i][1];
if(h==1)ans=100,end=1;
printf("%d\n",ans);
for(int i=1;i<=end;i++)puts("0");
return;
}
memset(f,-1,sizeof(f));//这样可以保证字典序最小,我也不太清楚
f[0][(1+w)>>1]=c[0][(1+w)>>1];//初值
int set=0,ans=0;
for(int i=1;i<=end;i++){//枚举时间
for(int j=1;j<=w;j++){//枚举空间
int k=j-2;if(k<0)k=0;
f[i][j]=_max(f[i-1][j-1],f[i-1][k],f[i-1][j],f[i-1][j+1],f[i-1][j+2])+c[i][j];
if(i==end && ans<f[i][j]){
ans=f[i][j];set=j;
}
if(f[i][j]==f[i-1][j+2]+c[i][j])s[i][j]=2;
if(f[i][j]==f[i-1][j+1]+c[i][j])s[i][j]=1;
if(f[i][j]==f[i-1][j]+c[i][j])s[i][j]=0;
if(f[i][j]==f[i-1][j-1]+c[i][j])s[i][j]=-1;
if(f[i][j]==f[i-1][k]+c[i][j])s[i][j]=-2;
}
}
printf("%d\n",ans);
//printf("%d %d\n",end,set);
Print(end,set);
}