zoukankan      html  css  js  c++  java
  • [ APIO 2015 ] 雅加达的摩天楼

    (\)

    (Description)


    (N)栋楼和(M)条狗,每条狗都有自己的初始地点(p_i)和跳跃距离(k_i),每条狗每次移动只能移动到当前坐标(pm k_i)的地方。

    现在(0)号狗处有一条信息,它要传给(1)号狗。只有当前掌握信息的狗可以移动,在楼处狗之间可以交接,求将信息传给(1)号总共最少需要跳跃多少次。

    • (N,Min [1,3 imes 10^4])

    (\)

    (Solution)


    洛谷数据有毒

    考虑暴力,直接通过每一个狗将其起点连接上所有通过该狗可以到达的地点,代价就是跳的次数,然后最短路。

    好了现在你在洛谷能过了 而且这比所谓正解快的不止两倍......

    显然边数是爆炸的,所以考虑优化建边。注意到如果给出的每一栋楼处都有一个(k_i=1)的狗,那边数就是(N^2)的。

    注意到这样的边每一条都重建了很多次,我们不妨直接拆点,把一张符合限制的"完全图建出来"。

    把每个点拆成(k)个点,第(i imes k+j)个点就代表第(i)个点一只(k_i=j)的狗处。那么如果把一个点拆出的点排在一列,那么同一行的点之间移动是自由的,如下图(发现一个生动的说法,相同层数的狗可以在高空乱JB走)边为双向:

    同时为了保证可以在任意处换狗,从高层下来到原始节点也连一条边,边权为(0)

    然后考虑狗的出现,有一条狗在(p_i)代表从(p_i)的原始节点可以上到高度为(k_i)层的位置,也直接连一条(0)边。

    再考虑(k_i)特别大的情况,会无意义的建立了很大的一个图。

    运用均值不等式的思想,进行阈值优化。只对(le sqrt N)的高度部分暴力建立新图,剩下的部分暴力建边,根据经典的分析边的级别都是(Nsqrt N)的,于是可以愉快的最短路了。

    (\)

    (Code)


    这题洛谷数据有毒......根号作为上界一直过不了,看了题解发现可以通过取(min)的方式控制上限,一路试过来发现上限为(1)的时候竟然最快......这不就是暴力吗......

    #include<cmath>
    #include<queue>
    #include<cstdio>
    #include<cctype>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define N 30010
    #define M 7000010
    #define R register
    #define gc getchar
    #define inf 1000000000
    using namespace std;
    
    bool vis[M];
    
    int n,m,lim=170,s,t,tot,hd[M],dis[M];
    
    struct edge{int w,to,nxt;}e[M<<1];
    
    inline void add(int u,int v,int w){
      e[++tot].to=v; e[tot].w=w;
      e[tot].nxt=hd[u]; hd[u]=tot;
    }
    
    inline int pos(int p,int h){return p*(lim+1)+h;}
    
    inline int rd(){
      int x=0; bool f=0; char c=gc();
      while(!isdigit(c)){if(c=='-')f=1;c=gc();}
      while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
      return f?-x:x;
    }
    
    queue<int> q;
    
    inline void spfa(){
      int totp=pos(n,lim);
      for(R int i=0;i<=totp;++i) dis[i]=inf;
      dis[s]=0; q.push(s);
      while(!q.empty()){
        int u=q.front();
        q.pop(); vis[u]=0;
        for(R int i=hd[u],v;i;i=e[i].nxt)
          if(dis[v=e[i].to]>dis[u]+e[i].w){
            dis[v]=dis[u]+e[i].w;
            if(!vis[v]) q.push(v),vis[v]=1;
          }
      }
    }
    
    int main(){
      n=rd(); m=rd();
      for(R int i=0;i<n;++i)
        for(R int j=1;j<=lim;++j) add(pos(i,j),pos(i,0),0);
      for(R int i=0;i<n;++i)
        for(R int j=1;j<=lim;++j)
          if(i+j<n){add(pos(i,j),pos(i+j,j),1);add(pos(i+j,j),pos(i,j),1);}
      for(R int i=1,p,k;i<=m;++i){
        p=rd(); k=rd();
        if(i==1) s=pos(p,0);
        if(i==2) t=pos(p,0);
        if(k<=lim) add(pos(p,0),pos(p,k),0);
        else{
          for(R int j=1;p+j*k<n;++j) add(pos(p,0),pos(p+j*k,0),j);
          for(R int j=1;p-j*k>=0;++j) add(pos(p,0),pos(p-j*k,0),j);
        }
      }
      spfa(); printf("%d",(dis[t]<inf)?dis[t]:-1);
      return 0;
    }
    
    
  • 相关阅读:
    Linux目录管理常用指令
    生成器
    Python上的MVC和MVT理解,请求头,请求体,请求行的理解
    sellect、poll、epoll
    冒泡法排序
    (android / IOS)
    发现一个bug如何定位是前端还是后台问题?
    ANR----以及如何定位是前端问题还是后台问题?
    给你一个web端项目你如何展开测试?
    给你一个app你如何展开测试?
  • 原文地址:https://www.cnblogs.com/SGCollin/p/9746140.html
Copyright © 2011-2022 走看看