• LOJ#539. 「LibreOJ NOIP Round #1」旅游路线


    n<=100,m<=1000的图,在此图上用油箱容量C<=1e5的车来旅行,旅行时,走一条边会耗一单伟油,在点i时,若油量<ci,则可以把油以pi的价格补到ci,pi<=n*n,ci<=1e5,现T<=1e5个询问:从Ai出发,带Yi<=n*n块钱走不少于Si<=1e9的路程,问最多剩多少钱。

    方法一:其实就是问从某个点出发,走路程Si,问最少花费。F(i,j,k)--从i出发,剩下j的油,走路程k最小花费,决策一下在i要不要加油即可。

    方法二:走路程Si问最小花费-->花费q问最长路程。F(i,j,q)--从i出发剩j的油,用q块钱最长路程,决策一下要不要在i加油即可。

    方法三:整个路程其实就是由几个加油处为中转点拼起来的,因此只用加油处的状态就可以勾勒整个过程,而加油处加完油后,油箱状态和之前没关系,可以省掉。F(i,q)--从i出发用q块钱最长路程,F(i,q)=max(F(j,q-pi)+G(i,j)),G(i,j)表示从i开始,到j,经过不超过min(ci,C)条路的最长路。

    G(i,j)的计算可以用倍增:W(i,j,k)表示i到j经过不超过2^k步的最长路程,用W来拼凑G。

    最后询问时,在F(Ai)数组里二分找F(Ai,j)>=Si的最小的j,得答案。

    有点复杂。。

     1 #include<stdio.h>
     2 #include<string.h>
     3 #include<stdlib.h>
     4 #include<math.h>
     5 #include<algorithm>
     6 //#include<iostream>
     7 using namespace std;
     8 
     9 bool isdigit(char c) {return c>='0' && c<='9';}
    10 int qread()
    11 {
    12     char c;int s=0,t=1;while (!isdigit(c=getchar())) (c=='-' && (t=-1));
    13     do s=s*10+c-'0'; while (isdigit(c=getchar())); return s*t;
    14 }
    15 int n,m,C,T;
    16 #define maxn 111
    17 #define maxm 2017
    18 struct Edge{int to,v,next;}edge[maxm];int first[maxn],le=2;
    19 void in(int x,int y,int v) {Edge &e=edge[le];e.to=y;e.v=v;e.next=first[x];first[x]=le++;}
    20 
    21 #define LL long long
    22 LL f[maxn][maxn*maxn],g[maxn][maxn],tmp[maxn][maxn],w[maxn][maxn][22],c[maxn],p[maxn];
    23 const LL inf=1e16;
    24 void prebz()
    25 {
    26     for (int i=1;i<=n;i++)
    27         for (int j=1;j<=n;j++)
    28             w[i][j][0]=-inf;
    29     for (int i=1;i<=n;i++)
    30     {
    31         w[i][i][0]=0;
    32         for (int j=first[i];j;j=edge[j].next)
    33         {
    34             const Edge &e=edge[j];
    35             w[i][e.to][0]=e.v;
    36         }
    37     }
    38     for (int k=1;k<=18;k++)
    39         for (int i=1;i<=n;i++)
    40             for (int j=1;j<=n;j++)
    41             {
    42                 w[i][j][k]=-inf;
    43                 for (int x=1;x<=n;x++)
    44                     w[i][j][k]=max(w[i][j][k],w[i][x][k-1]+w[x][j][k-1]);
    45             }
    46     for (int i=1;i<=n;i++)
    47     {
    48         int o=min(c[i],1ll*C);
    49         for (int j=1;j<=n;j++) g[i][j]=-inf;
    50         g[i][i]=0;
    51         for (int k=18;k>=0;k--) if (o&(1<<k))
    52         {
    53             for (int j=1;j<=n;j++) tmp[i][j]=-inf;
    54             for (int j=1;j<=n;j++)
    55                 for (int x=1;x<=n;x++)
    56                     tmp[i][j]=max(tmp[i][j],g[i][x]+w[x][j][k]);
    57             for (int j=1;j<=n;j++) g[i][j]=tmp[i][j];
    58         }
    59     }
    60 }
    61 
    62 void predp()
    63 {
    64     for (int j=0;j<=n*n;j++)
    65         for (int i=1;i<=n;i++)
    66         {
    67             f[i][j]=0;
    68             if (j>=p[i]) for (int x=1;x<=n;x++) f[i][j]=max(f[i][j],f[x][j-p[i]]+g[i][x]);
    69         }
    70 }
    71 
    72 void init()
    73 {
    74     n=qread(),m=qread(),C=qread(),T=qread();
    75     for (int i=1;i<=n;i++) p[i]=qread(),c[i]=qread();
    76     for (int i=1,x,y,z;i<=m;i++)
    77     {
    78         x=qread(),y=qread(),z=qread();
    79         in(x,y,z);
    80     }
    81 }
    82 
    83 int main()
    84 {
    85     init();
    86     prebz();
    87     predp();
    88     while (T--)
    89     {
    90         int x=qread(),y=qread(),z=qread();
    91         int t=lower_bound(f[x]+1,f[x]+1+n*n,z)-f[x];
    92         if (t<=y) printf("%d
    ",y-t);
    93         else puts("-1");
    94     }
    95     return 0;
    96 }
    View Code
  • 相关阅读:
    Java Stream 流(JDK 8 新特性)
    Java EnumMap 实现类
    Java 设计模式
    Java lambda 表达式详解(JDK 8 新特性)
    Java forEach 方式遍历集合(Java 8 新特性)
    Java 单例设计模式
    Java public 和 private 访问修饰符
    == 、equals 、hashcode
    String
    ClassLoader 的分类及加载顺序
  • 原文地址:https://www.cnblogs.com/Blue233333/p/7791577.html
Copyright © 2020-2023  润新知