Luogu6005 [USACO20JAN]Time is Mooney G 题解

题目传送门

第一眼看到题面时可能觉得需要用 dijstra 或分层图之类,但注意到数据范围很小(都是 \(\leqslant1000\)),因此考虑好写的 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 @ 2021-07-22 12:39  BFNewdawn  阅读(49)  评论(0编辑  收藏  举报