P1081 开车旅行 题面较为啰嗦。大概概括:一个数列,只能从一个点向后走,两种方案:A.走到和自己差的绝对值次小的点B.走到和自己差的绝对值最小点;花费为此差绝对值;若干询问从规定点向后最多花费$X$,且以移动方式A开始每走一次切换一次方式。求以A、B方式各花费多少。
不看题解切紫题一遍过了,兴奋~然而连想带写花了四小时左右,真要在noip考场上怕不是要凉。。。我太菜了QwQ
先看第一问,找比值最小点,实际上就是拆成$N$个询问,扔到第二问的询问里面做掉的说。所以主要看对于询问点怎么向后找终止点。可以猜出应该是$O(logN)$一次询问,所以就要求高效的跳法。
考虑A若干次之后走到后面一个点,从这个点继续走,这样一个状态,很多询问都可能经历。所以对于一个点,希望预处理出以他为起点有关的信息。
维护从他开始的终点?显然不行。
若最远点$T_0$,可能当下到这起点已花了一些代价,由于代价制限导致走不到最远,大概能走到$T_1 < T_0$。也就是说,$S$~$T_1$这一段是我可以走过的,$T_1$之后都到不了。
所以可以根据实际情况二分查找最远点。实现起来,就是个倍增,到目标点要走$k$次,总是可以拆成走二的指数幂次叠加,枚举当前走的$2^i$次,可行就跳,不可行就呆原地。
这个是处理询问的方法。所以瓶颈就在于如何预处理倍增数组。坑死我了。
设计状态$fa[i][j],fb[i][j],to[i][j]$表示从$i$点出发,走$2^j$次,A、B各自花费,以及讫点。
对于底层$to[i][0]$,只采用A方式移动,找出后面次小代价即可。单独处理。
对于次底层$f[i][1]$,开始用AB轮流交替方式移动,所以在底层要顺便处理以B方式移动一次的相关信息,在这一层与A合并。
之后,由于每个状态都是走偶数次的,涉及转移状态都是以A开始的,比如我移动4次,由前2次和后2次拼接,这两段都是以A开始的。所以直接合并即可。
提一下最底层找相邻点的几种方法:
- 每个点后面离他最近的。。前驱后继?平衡树?考虑用set来替代。找出大于他的两个,小于他的两个(没有则设为0),排一下序处理出来
- set找4个点同上,然后。。分类讨论。。我的弱智方法。。。。qwq
- 双向链表。可以将数组排序,将其用数组模拟成链表,之后,和每个点相邻的,虽然不一定是原来数组中他后面的元素,但是对于原数组1号,他在排序数组中相邻的肯定是前驱后继。找出之后将之从链表中删除,再考虑原数组的2号点,这时就不存在1号点的干扰了,后面同理。
常数稍大,但不影响能过,反正都是$O((N+M)logN)$的。相关细节注意一下即可,如超出1e9提前特判掉等等。
1 #include2 #include 3 #include 4 #include 5 #include 6 #include<set> 7 #define dis first 8 #define pos second 9 #define dbg(x) cerr<<#x<<" = "< 10 #define _dbg(x,y) cerr<<#x<<" = "< 11 using namespace std; 12 typedef pair<int,int> pii; 13 typedef long long ll; 14 template inline char MIN(T&A,T B){return A>B?A=B,1:0;} 15 template inline char MAX(T&A,T B){return A1:0;} 16 template inline T _min(T A,T B){return AA:B;} 17 template inline T _max(T A,T B){return A>B?A:B;} 18 namespace io{ 19 const int SIZE = (1 << 21) + 1; 20 char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - 1, c, qu[55]; int f, qr; 21 #define gc() (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++) 22 inline void flush (){fwrite (obuf, 1, oS - obuf, stdout);oS = obuf;} 23 inline void putc (char x){*oS ++ = x;if (oS == oT) flush ();} 24 template <class I> 25 inline void read(I &x) {for (f = 1, c = gc(); c < '0' || c > '9'; c = gc()) if (c == '-') f = -1; 26 for (x = 0; c <= '9' && c >= '0'; c = gc()) x = x * 10 + (c & 15); x *= f;} 27 template <class I> 28 inline void print (I x){ 29 if (!x) putc ('0'); if (x < 0) putc ('-'), x = -x;while(x) qu[++ qr] = x % 10 + '0', x /= 10;while (qr) putc (qu[qr--]);} 30 struct Flusher_ {~Flusher_(){flush();}}io_flusher_; 31 } 32 using io::read; 33 using io::putc; 34 using io::print; 35 const int N=100000+7,INF=0x3f3f3f3f; 36 set s; 37 int h[N],fa[N][18],fb[N][18],to[N][18],to2[N],disb[N]; 38 int n,Q,T,m; 39 40 inline void preprocess_the_bottom(){ 41 set ::iterator up,down; 42 int d0,d1,d2,d3,p0,p1,p2,p3; 43 m=__lg(n); 44 fa[n][0]=fb[n][0]=disb[n]=0;to[n][0]=to2[n]=n+1;s.insert(make_pair(h[n],n)); 45 for(register int i=n-1;i;--i){ 46 down=up=s.lower_bound(make_pair(h[i],0)); 47 d0=d1=d2=d3=0,p0=p1=p2=p3=n+1; 48 if(down!=s.begin())--down,d0=h[i]-(*down).dis,d0>1e9?(d0=0):(p0=(*down).pos);//下侧第一 49 if(down!=s.begin())--down,d2=h[i]-(*down).dis,d2>1e9?(d2=0):(p2=(*down).pos);//下侧第二 50 if(up!=s.end())d1=(*up).dis-h[i],d1>1e9?(d1=0):(p1=(*up).pos);//上侧第一 51 if(up!=s.end()&&++up!=s.end())d3=(*up).dis-h[i],d3>1e9?(d3=0):(p3=(*up).pos);//上侧第二 52 if(d0){ 53 if(d1){//两侧都有 54 if(d1<d0){ 55 disb[i]=d1,to2[i]=p1; 56 if(d3&&d3 0]=d3,to[i][0]=p3;//上侧第二为次近 57 else fa[i][0]=d0,to[i][0]=p0;//下侧第一为次近 58 } 59 else{ 60 disb[i]=d0,to2[i]=p0; 61 if(d2&&d2<=d1)fa[i][0]=d2,to[i][0]=p2;//下侧第二为次近 62 else fa[i][0]=d1,to[i][0]=p1;//上侧第一为次近 63 } 64 } 65 else{//只有下侧 66 disb[i]=d0,to2[i]=p0; 67 fa[i][0]=d2,to[i][0]=p2; 68 } 69 } 70 else disb[i]=d1,to2[i]=p1,fa[i][0]=d3,to[i][0]=p3;//只有上侧或者两侧都没有 71 // dbg(i);_dbg(disb[i],to2[i]);_dbg(fa[i][0],to[i][0]); 72 s.insert(make_pair(h[i],i)); 73 } 74 to2[n+1]=n+1;for(register int i=0;i<=m;++i)to[n+1][i]=n+1; 75 } 76 77 inline void preprocess(){ 78 for(register int i=1;i<=n;++i)fa[i][1]=fa[i][0],fb[i][1]=disb[to[i][0]],to[i][1]=to2[to[i][0]]; 79 for(register int i=2;i<=m;++i){ 80 for(register int j=1;j<=n;++j){ 81 fa[j][i]=fa[j][i-1]+fa[to[j][i-1]][i-1],fb[j][i]=fb[j][i-1]+fb[to[j][i-1]][i-1];to[j][i]=to[to[j][i-1]][i-1]; 82 fa[j][i]+0ll+fb[j][i]>1e9?(fa[j][i]=0,fb[j][i]=0,to[j][i]=n+1):0; 83 } 84 } 85 } 86 int xa,xb; 87 inline void Query(int x,int tot){ 88 xa=xb=0; 89 for(register int i=m;~i;--i)if(to[x][i]<=n&&fa[x][i]+fb[x][i]<=tot)tot-=fa[x][i]+fb[x][i],xa+=fa[x][i],xb+=fb[x][i],x=to[x][i]; 90 } 91 int x,tot,p,q,ans; 92 int main(){//freopen("test.in","r",stdin);freopen("test.out","w",stdout); 93 read(n);for(register int i=1;i<=n;++i)read(h[i]); 94 preprocess_the_bottom();preprocess(); 95 read(Q);Query(1,Q);p=xa,q=xb,ans=1; 96 for(register int i=2;i<=n;++i){ 97 Query(i,Q); 98 if(!xb){if(!q)if(h[ans] continue;} 99 if(xa*1ll*q i; 100 else if(xa*1ll*q==xb*1ll*p)if(h[ans] i; 101 } 102 print(ans);read(T);putc('\n'); 103 for(register int i=1;i<=T;++i){ 104 read(x),read(tot);Query(x,tot); 105 print(xa),putc(' '),print(xb),putc('\n'); 106 } 107 return 0; 108 }