• P1081 [NOIP2012]开车旅行[倍增]


    P1081 开车旅行    题面较为啰嗦。大概概括:一个数列,只能从一个点向后走,两种方案:A.走到和自己差的绝对值次小的点B.走到和自己差的绝对值最小点;花费为此差绝对值;若干询问从规定点向后最多花费$X$,且以移动方式A开始每走一次切换一次方式。求以A、B方式各花费多少。


    不看题解切紫题一遍过了,兴奋~然而连想带写花了四小时左右,真要在noip考场上怕不是要凉。。。我太菜了QwQ

    先看第一问,找比值最小点,实际上就是拆成$N$个询问,扔到第二问的询问里面做掉的说。所以主要看对于询问点怎么向后找终止点。可以猜出应该是$O(log N)$一次询问,所以就要求高效的跳法。

    考虑A若干次之后走到后面一个点,从这个点继续走,这样一个状态,很多询问都可能经历。所以对于一个点,希望预处理出以他为起点有关的信息。

    维护从他开始的终点?显然不行。

    若最远点$T_0$,可能当下到这起点已花了一些代价,由于代价制限导致走不到最远,大概能走到$T_1 < T_0$。也就是说,$Ssim 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)log N)$的。相关细节注意一下即可,如超出1e9提前特判掉等等。

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<cmath>
      5 #include<algorithm>
      6 #include<set>
      7 #define dis first
      8 #define pos second
      9 #define dbg(x) cerr<<#x<<" = "<<x<<endl
     10 #define _dbg(x,y) cerr<<#x<<" = "<<x<<"   "<<#y<<" = "<<y<<endl
     11 using namespace std;
     12 typedef pair<int,int> pii;
     13 typedef long long ll;
     14 template<typename T>inline char MIN(T&A,T B){return A>B?A=B,1:0;}
     15 template<typename T>inline char MAX(T&A,T B){return A<B?A=B,1:0;}
     16 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
     17 template<typename T>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<pii> 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<pii>::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<d0)fa[i][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]<h[i])ans=i;continue;}
     99         if(xa*1ll*q<xb*1ll*p)p=xa,q=xb,ans=i;
    100         else if(xa*1ll*q==xb*1ll*p)if(h[ans]<h[i])ans=i;
    101     }
    102     print(ans);read(T);putc('
    ');
    103     for(register int i=1;i<=T;++i){
    104         read(x),read(tot);Query(x,tot);
    105         print(xa),putc(' '),print(xb),putc('
    ');
    106     }
    107     return 0;
    108 }
  • 相关阅读:
    css3动画事件 animationend animationiteration animationstart
    dom对象---增加class属性,去除class属性
    数组的indexOf() 方法
    line-height中的五种取值方式和继承
    html 中line-height相关的四种box模型
    真正的能理解CSS中的line-height,height与line-height
    background-size:contain与cover的区别
    激活win10系统
    table-layout:fixed 应用
    js数组fill()方法
  • 原文地址:https://www.cnblogs.com/saigyouji-yuyuko/p/10740308.html
Copyright © 2020-2023  润新知