[题解]luogu_P1070道路游戏(堆dp

普及组T4

还有点不懂的先咕着

#include<bits/stdc++.h>
using namespace std;
const int maxn=1009;
int n,m,p,ans=-1e9;
int sum[maxn][maxn],gd[maxn][maxn],cs[maxn],rec[maxn][maxn];//rec[i][j]=f[i]-sum[i][j]-cost[j]
int pre[maxn][maxn],f[maxn];
struct node{
    int x,st;//rec值和时间 
    node(){}
    node(int xx,int tt){
        x=xx;st=tt;
    }
    bool operator <(const node&t)const{
        return x<t.x;
    }
};
priority_queue<node>q[maxn];
void upd(int s,int now){
    node tmp=q[s].top();
    while(now-tmp.st>=p){
        q[s].pop();
        tmp=q[s].top();
    }
}
int main(){
    scanf("%d%d%d",&n,&m,&p);
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
    scanf("%d",&gd[i%n][j]);
    for(int i=0;i<n;i++)scanf("%d",&cs[i]);
    for(int i=1;i<=m;i++){
        for(int j=0;j<n;j++)
        sum[i][j]=sum[i-1][(j-1+n)%n]+gd[j][i];
    }
    for(int i=0;i<n;i++)pre[0][(i-1+n)%n]=i;//储存起始点,用于判断属于哪个队列 
    for(int i=0;i<n;i++){
        rec[0][i]=-cs[i];
        q[pre[0][i]].push(node(-cs[i],0));
    }
    memset(f,~0x3f,sizeof(f));
    for(int i=1;i<=m;i++){
        int tmp=-1e9;
        for(int j=0;j<n;j++){//更新答案以及上一阶段的最优值 
            f[i]=max(f[i],rec[i-1][(j-1+n)%n]+sum[i][j]);
            ans=max(ans,f[i]);
            tmp=max(tmp,f[i]);
        }
        for(int j=0;j<n;j++){
            pre[i][j]=pre[i-1][(j-1+n)%n];
            q[pre[i][j]].push(node(tmp-sum[i][j]-cs[j],i));
            while(i-q[pre[i][j]].top().st>=p)q[pre[i][j]].pop();//排除过时决策,i递增所以正确 
            rec[i][j]=q[pre[i][j]].top().x;
        }
    }
    printf("%d",ans);
}

 

posted @ 2019-10-14 17:34  羊肉汤泡煎饼  阅读(123)  评论(0编辑  收藏  举报