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 }
以上是关于LOJ#539. 「LibreOJ NOIP Round #1」旅游路线的主要内容,如果未能解决你的问题,请参考以下文章
loj536「LibreOJ Round #6」花札(二分图博弈)
[LOJ#525]「LibreOJ β Round #4」多项式