Loading [MathJax]/jax/element/mml/optable/SuppMathOperators.js

Luogu6005 [USACO20JAN]Time is Mooney G 题解

题目传送门

第一眼看到题面时可能觉得需要用 dijstra 或分层图之类,但注意到数据范围很小(都是 ),因此考虑好写的 DP

首先当然需要使用邻接表存图。

不妨设 f_{i,j} 为第 i 天在第 j 个城市所获利润,易得状态转移方程

f_{i,j}=\max(f_{i,j},f_{i-1,e[i].to})

但是这还没完,还有两个问题需要解决:

  1. 会以 T^2\times C 的速度扣钱。

    不妨在每次外层循环后处理 ans,有:

    ans=\max(ans,f[i][1]-c\times i^2);

  2. 外层循环没有明确边界。

    最大是 1000,以此为边界即可。注意:有的人可能习惯设 N=1010 ,这会导致 i=N 时 RE,应该 N-10

View code:

#include<bits/stdc++.h>
using namespace std;

#define int long long
#define ri register int
#define il inline

const int INF=0x7fffffff,N=1010;
int n,m,c,ans=0;
int v[N];
int cnt,head[N];
int f[N][N];
struct Edge{
    int to,nxt;
}e[N<<2];

il ll read(){
    ll x=0,y=1;
    char c=getchar();
    while(c<'0'||c>'9'){
        if(c=='-')
            y=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9'){
        x=x*10+c-'0';
        c=getchar();
    }
    return x*y;
}

il void add(int u,int v){
    e[++cnt]=(Edge){v,head[u]};
    head[u]=cnt;
}

signed main(){
    memset(f,-1,sizeof(f));
    n=read(),m=read(),c=read();
    for(ri i=1;i<=n;i++)
        v[i]=read();
    for(ri i=1;i<=m;i++){
        int u=read(),v=read();
        add(u,v);//有向图
    }
    f[0][1]=0;
    for(ri i=1;i<=N-10;i++){
        for(ri j=1;j<=n;j++){
            for(ri k=head[j];k;k=e[k].nxt){
				if(~f[i-1][e[k].to])
					f[i][j]=max(f[i][j],f[i-1][e[k].to]+v[j]);
            }
        }
        ans=max(ans,f[i][1]-(c*i*i));
    }
    printf("%lld",ans);
    return 0;
}
posted @   BFNewdawn  阅读(50)  评论(0)    收藏  举报
点击右上角即可分享
微信分享提示