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 }

时间: 2024-10-30 01:51:31

LOJ#539. 「LibreOJ NOIP Round #1」旅游路线的相关文章

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

哎一开始看错题了啊T T...最近状态一直不对...最近很多傻逼题都不会写了T T 考虑距离较大肯定不能塞进状态...钱数<=n^2能够承受, 油量再塞就不行了...显然可以预处理出点i到j走ci步的最长距离(一开始以为一条路耗油为路的长度T T), 这个是经典题, 倍增求就好了...然后就可以转移了呀T T 最后二分就好了呀T T... 我怎么这么菜啊, 还写了好久T T... 一开始还写成n^4logn TLE了半天没查到错 #include<iostream> #include&l

LibreOJ #507. 「LibreOJ NOI Round #1」接竹竿

二次联通门 : LibreOJ #507. 「LibreOJ NOI Round #1」接竹竿 /* LibreOJ #507. 「LibreOJ NOI Round #1」接竹竿 dp 记录一下前驱就好了 再随便用前缀和优化一下 O(N) */ #include <iostream> #include <cstdio> const int BUF = 100000010; char Buf[BUF], *buf = Buf; inline long long max (long

loj #535. 「LibreOJ Round #6」花火 树状数组求逆序对+主席树二维数点+整体二分

$ \color{#0066ff}{ 题目描述 }$ 「Hanabi, hanabi--」 一听说祭典上没有烟火,Karen 一脸沮丧. 「有的哦-- 虽然比不上大型烟花就是了.」 还好 Shinobu 早有准备,Alice.Ayaya.Karen.Shinobu.Yoko 五人又能继续愉快地玩耍啦! 「噢--!不是有放上天的烟花嘛!」Karen 兴奋地喊道. 「啊等等--」Yoko 惊呼.Karen 手持点燃引信的烟花,「嗯??」 Yoko 最希望见到的是排列优美的烟火,当然不会放过这个机会-

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

试题描述 给定一个正整数 k,你需要寻找一个系数均为 0 到 k?1 之间的非零多项式 f(x),满足对于任意整数 x 均有 f(x) mod k=0.你给出的多项式次数不能超过 60000,且最高次系数必须非 0. 输入 输入一行,包含一个正整数 k. 输出 若无解,则只输出一个整数 ?1.否则首先输出一个整数 n 表示你寻找的多项式的次数,随后 n+1 个整数按照从低位到高位的顺序输出多项式的系数. 在此之后的输出将被忽略. 输入示例 3 输出示例 4 0 1 2 2 1 数据规模及约定 1

「美团 CodeM 初赛 Round B」景区路线规划 概率DP

题意 游乐园被描述成一张 n 个点,m 条边的无向图(无重边,无自环).每个点代表一个娱乐项目,第 i 个娱乐项目需要耗费 ci 分钟的时间,会让小 y 和妹子的开心度分别增加 h1i ,h2i ,他们俩初始的开心度都是 0 .每条边代表一条路,第 i 条边连接编号为 xi , yi 的两个娱乐项目,从 xi 走到 yi 或者从 yi 走到 xi 耗费的时间都是 ti 分钟.小 y 和妹子预计在游乐园里玩 k 分钟.最开始的时候,小 y 和妹子会等概率的随机选择一个娱乐项目开始玩,每玩完一个项目

[LOJ 6249]「CodePlus 2017 11 月赛」汀博尔

Description 有 n 棵树,初始时每棵树的高度为 H_i,第 i 棵树每月都会长高 A_i.现在有个木料长度总量为 S 的订单,客户要求每块木料的长度不能小于 L,而且木料必须是整棵树(即不能为树的一部分).现在问你最少需要等多少个月才能满足订单. Input 第一行 3 个用空格隔开的非负整数 n,S,L,表示树的数量.订单总量和单块木料长度限制.第二行 n 个用空格隔开的非负整数,依次为 H1,H2,…,Hn.第三行 n 个用空格隔开的非负整数,依次为 A1,A2,…,An. Ou

LibreOJ #515. 「LibreOJ β Round #2」贪心只能过样例

二次联通门 : LibreOJ #515. 「LibreOJ β Round #2」贪心只能过样例 /* LibreOJ #515. 「LibreOJ β Round #2」贪心只能过样例 很显然 贪心方程哦不 dp方程为 f[i][j]=f[i-1][j-k*k] 但是这样的话复杂度就是O(N ^ 5) 那么就用bitset优化一下 就ok了 */ #include <iostream> #include <cstdio> #include <bitset> void

LibreOJ「LibreOJ β Round #4」 游戏

二次联通门 : LibreOJ「LibreOJ β Round #4」 游戏 /* LibreOJ「LibreOJ β Round #4」 游戏 找找规律就会发现.. 当有X的时候,答案跟X个数的奇偶有关 否则就求一下逆序对就好了.. 由于SB的错误..WA了3发才过 然后就签完到走人了 */ #include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #defi

LibreOJ #514. 「LibreOJ β Round #2」模拟只会猜题意

二次联通门 : LibreOJ #514. 「LibreOJ β Round #2」模拟只会猜题意 /* LibreOJ #514. 「LibreOJ β Round #2」模拟只会猜题意 本想打个暴力找找规律 结果交上去就A了... 读入所有数 处理出前缀和 然后枚举区间长度 处理处1~n的答案 后O(1)查询即可 复杂度O(n^2 + m) */ #include <iostream> #include <cstring> #include <cstdio> voi