「LibreOJ NOIP Round #1」旅游路线

「LibreOJ NOIP Round #1」旅游路线


题目链接

做法:

  1. 首先肯定要预处理些东西,来使单词询问达到(o(logn))或者(o(1))的复杂度,又因为距离这个东西的范围太大,我们考虑预处理一些费用相关的东西。
  2. 考虑(dp[s][j])表示从s出发花费j元,走的最长的距离,如果求出了这个东西,显然距离随费用单调递增,直接在(dp[s])内二分即可。
  3. 可以列出方程:(dp[s][j] = max(dp[t][j-p[s]]+dis[s][t])), (dis[s][t])表示从s到t,在s加一次油走到t最长经过的距离。
  4. 考虑如何计算(dis[s][t]),用(dis[s][t][C])表示从s到t用不超过C的油最长的距离,直接可以folyd求出答案,但是显然会tle,于是可以采用倍增 floyd 的方法预处理数 (dis[s][t][1,2,4,8...]) 即预先计算 (dis[s][t][k]) 表示从 s 到 t 初始油量为 (2^k) 能走的最长距离,然后就可以对于每个起点,合并出它的答案。注意在预处理时不用考虑油量的限制。

深刻的感受到了要注意细节,这份时间爆炸的代码换个头文件都能tle。。。恳请知道原因的大佬赐教。

#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;++i)
typedef long long ll;
const int N = 110;
const int inf = 0x3f3f3f3f;
inline int read() {
    char c=getchar(); int x=0,f=1;
    while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    while(isdigit(c)){x=x*10+c-'0';c=getchar();}
    return x*f;
}
using namespace std;
int n,m,C,T,p[N],c[N];

int dis[17][N][N], dp[N][N*N];
void init_dis() {
    rep(s,1,16) {
        memcpy(dis[s],dis[s-1],sizeof(dis[s]));
        rep(k,1,n)rep(i,1,n)if(dis[s-1][i][k]!=-1)rep(j,1,n)if(dis[s-1][k][j]!=-1){
            dis[s][i][j]=max(dis[s][i][j],dis[s-1][i][k]+dis[s-1][k][j]);
        }
    }
}
int d[N][N],ans[N][N],tmp[17][N][N];
void getdis(int s) {
    memset(ans,-1,sizeof(ans));
    rep(i,1,n)ans[i][i]=0;
    memset(tmp,-1,sizeof(tmp));
    rep(x,0,16)if(min(c[s],C)&(1<<x)){
        rep(i,1,n)tmp[x][i][i] = 0;
        rep(k,1,n)rep(i,1,n)if(ans[i][k]!=-1)rep(j,1,n)if(dis[x][k][j]!=-1){
            tmp[x][i][j] = max(tmp[x][i][j],ans[i][k]+dis[x][k][j]);
        }
        rep(i,1,n)rep(j,1,n)ans[i][j]=tmp[x][i][j];
    }
    rep(i,1,n) d[s][i] = ans[s][i];
}
void init() {
    init_dis();
    rep(i,1,n)getdis(i);
    rep(j,0,n*n)rep(s,1,n)rep(t,1,n)if(j>=p[s]&&d[s][t]!=-1){
        dp[s][j] = max(dp[s][j],dp[t][j-p[s]]+d[s][t]);
    }
}
int main() {
    n = read(), m =read(), C = read(), T=read();
    rep(i,1,n) p[i]=read(),c[i]=read();
    int x,y,l;
    memset(dis,-1,sizeof(dis));
    rep(i,1,n)rep(s,0,16)dis[s][i][i]=0;
    rep(i,1,m) x=read(),y=read(),dis[0][x][y]=read();
    init();
    while(T--) {
        int s,q,d;
        s=read(),q=read(),d=read();
        int cs = lower_bound(dp[s],dp[s]+1+n*n,d) - dp[s];
        if(dp[s][cs]>=d&&q>=cs&&cs<=n*n)printf("%d
",q-cs);
        else puts("-1");
    }
    return 0;
}

原文地址:https://www.cnblogs.com/RRRR-wys/p/9432047.html