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

Posted Blue233333

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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\n",y-t);
93         else puts("-1");
94     }
95     return 0;
96 }
View Code

 

以上是关于LOJ#539. 「LibreOJ NOIP Round #1」旅游路线的主要内容,如果未能解决你的问题,请参考以下文章

loj536「LibreOJ Round #6」花札(二分图博弈)

[LOJ#525]「LibreOJ β Round #4」多项式

LOJ 「LibreOJ β Round #4」子集

loj526「LibreOJ β Round #4」子集

loj516 「LibreOJ β Round #2」DP 一般看规律

$loj530 [LibreOJ eta Round #5]$ 最小倍数 数论