NOIP2012提高组开车旅行 倍增
Posted CzYoL
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NOIP2012提高组开车旅行 倍增相关的知识,希望对你有一定的参考价值。
题目分析
朴素的做法就是预处理下一个目的地,然后跑模拟,超时。
本题最重要的考点是倍增优化。设$fa[i][j]$表示a从i出发行驶$2^j$“次”后行驶的路程,$fb[i][j]$表示从i出发行驶$2^j$“次”后行驶的路程,注意这里的"次",a、b交替行驶。$f[i][j]$表示从i出发a、b交替$2^j$“次”后行驶到的城市编号。
显然有$fa[i][j] = fa[i][j - 1] + fa[f[i][j - 1]][j - 1], fb = fb[i][j - 1] + fb[f[i][j - 1]], f[i][j] = ff[i][j - 1]][j - 1]$。只需要用set求出前驱后继和次前驱后继,就能正确预处理出来。最后在路径上跑倍增就行。
code
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<string> #include<algorithm> #include<set> using namespace std; const int N = 1e5 + 5; int n, x0, m, nxta[N], nxtb[N], f[N][30]; typedef long long ll; ll fa[N][30], fb[N][30]; struct node2{ int h, pos; inline bool operator < (const node2 &b) const{ return h < b.h; } }data[N]; struct node{ int pos, dis; inline bool operator < (const node &b) const{ if(dis != b.dis) return dis < b.dis; return data[pos].h < data[b.pos].h; } }t[10]; set<node2> S; inline int read(){ int i = 0, f = 1; char ch = getchar(); for(; (ch < ‘0‘ || ch > ‘9‘) && ch != ‘-‘; ch = getchar()); if(ch == ‘-‘) f = -1, ch = getchar(); for(; ch >= ‘0‘ && ch <= ‘9‘; ch = getchar()) i = (i << 3) + (i << 1) + (ch - ‘0‘); return i * f; } inline void wr(ll x){ if(x < 0) putchar(‘-‘), x = -x; if(x > 9) wr(x / 10); putchar(x % 10 + ‘0‘); } inline void Find(int x){ int cnt = 0; set<node2>::iterator it = S.find(data[x]); if(it != S.begin()){ --it; t[++cnt] = (node){it->pos, abs(data[x].h - it->h)}; if(it != S.begin()) { --it; t[++cnt] = (node){it->pos, abs(data[x].h - it->h)}; ++it; } ++it; } if((++it) != S.end()){ t[++cnt] = (node){it->pos, abs(it->h - data[x].h)}; if((++it) != S.end()){ t[++cnt] = (node){it->pos, abs(it->h - data[x].h)}; --it; } --it; } sort(t + 1, t + cnt + 1); nxtb[x] = t[1].pos; if(cnt > 1) nxta[x] = t[2].pos; } inline void init(){ for(int i = 1; i <= n; i++){ int na = nxta[i], nb = nxtb[na]; fa[i][0] = na ? abs(data[na].h - data[i].h) : 0; fb[i][0] = nb ? abs(data[nb].h - data[na].h) : 0; f[i][0] = nb; } for(int j = 1; j <= 20; j++) for(int i = 1; i <= n; i++){ f[i][j] = f[f[i][j - 1]][j - 1]; fa[i][j] = fa[i][j - 1] + fa[f[i][j - 1]][j - 1]; fb[i][j] = fb[i][j - 1] + fb[f[i][j - 1]][j - 1]; } } inline void query(int s, ll x, ll &na, ll &nb){ for(int i = 20; i >= 0; i--) if(f[s][i] && fa[s][i] + fb[s][i] <= x){ na += fa[s][i], nb += fb[s][i]; x -= fa[s][i] + fb[s][i]; s = f[s][i]; } int posa = nxta[s], d = abs(data[s].h - data[posa].h); if(posa && d <= x) na += d; } int main(){ n = read(); for(int i = 1; i <= n; i++) data[i] = (node2){read(), i}; for(int i = n; i >= 1; i--){ S.insert(data[i]); if(i ^ n) Find(i); } init(); x0 = read(); int ans = 0; ll ansa = 0, ansb = 0; for(int i = 1; i <= n; i++){ ll na = 0, nb = 0; query(i, x0, na, nb); if(!ans || ansa * nb > ansb * na) ans = i, ansa = na, ansb = nb; } wr(ans), putchar(‘\n‘); m = read(); for(int i = 1; i <= m; i++){ ll na = 0, nb = 0; int st = read(), x = read(); query(st, x, na, nb); wr(na), putchar(‘ ‘), wr(nb), putchar(‘\n‘); } return 0; }
以上是关于NOIP2012提高组开车旅行 倍增的主要内容,如果未能解决你的问题,请参考以下文章