zoukankan      html  css  js  c++  java
  • P3645/BZOJ4070 [APIO2015]雅加达的摩天楼

    显然任意一种doge都只会单向行走且最多使用一次。

    假设p<=√n,那么总状态不超过n√n;

    假设p>√n,因为任意一个doge行走不超过n/p<√n步,总状态不超过m√n。

    于是暴力bfs,bitset判重即可。

    代码如下

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<string>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<bitset>
    #include<vector>
    using namespace std;
    typedef long long ll;
    const int N=3e4+10,M=2e7+10;
    struct node{
        int id,p,step;node(){};
        node(int _id,int _p,int _step){
            id=_id;p=_p;step=_step;
        }
    };
    int n,m,s,t,tot,l=1,r,bl[N],v[N],head[N],ver[N*2],next[N*2];node q[M];std::bitset<N> vis[N];
    inline ll read(){
        ll x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
        return x*f;
    }
    inline void add(int x,int y){
        ver[++tot]=y;next[tot]=head[x];head[x]=tot;
    }
    inline void insert(int x,int p,int step){
        if(v[x]!=1){
            v[x]=1;
            for(int i=head[x];i;i=next[i]){
                int sp=ver[i];
                if(!vis[x].test(sp)){
                    vis[x].set(sp);q[++r]=(node(x,sp,step));
                }
            }    
        }
        if(!vis[x].test(p)){
            vis[x].set(p);q[++r]=(node(x,p,step));
        }
    }
    int main(){
        n=read();m=read();
        for(int i=1;i<=m;i++){
            int b=read(),p=read();
            if(i==1) s=b;
            if(i==2) t=b;
            add(b,p);
        }
        if(s==t) return printf("0
    "),0;
        v[s]=1;
        for(int i=head[s];i;i=next[i]){
            int p=ver[i];
            if(!vis[s].test(p)){
                vis[s].set(p);q[++r]=(node(s,p,0));
            }
        }
        while(l<=r){
            node now=q[l++];
            int x=now.id,p=now.p,step=now.step;
            if(x-p==t||x+p==t) return printf("%d
    ",step+1),0;
            if(x>=p) insert(x-p,p,step+1);if(x+p<=n-1) insert(x+p,p,step+1);
        }
        return printf("-1
    "),0;
    }

    但不知为何此题BZOJ上的数据有毒,明明UOJ上的强化数据都能轻松通过,希望大佬指出错误……

    于是我们需要新的姿势qaq

    假设p<=√n,那么总状态不超过n√n,预处理出关于len<=√n的子图,建边时有原图向子图中对应的点连一条边。

    假设p>√n,,直接原图上暴力建边即可。

    (有什么区别吗qaq)

    同时容易发现这个图比较偏向于稠密图,spfa在大数据下更优于dijkstra

    另外吐槽下这题空间感人肺腑,常规建法要用时间换下空间。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<string>
    #include<cstring>
    #include<cmath>
    #include<queue>
    using namespace std;
    typedef long long ll;
    const int N=3e4+10;
    int n,m,s,t,p,tot,dis[N*105],vis[N*105],head[N*105],ver[N*505],next[N*505],edge[N*505];queue<int> q;
    inline ll read(){
        ll x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
        return x*f;
    }
    inline int id(int i,int j){
        return i*n+j;
    }
    inline void add(int x,int y,int z){
        ver[++tot]=y;edge[tot]=z;next[tot]=head[x];head[x]=tot;
    }
    inline void spfa(){
        memset(dis,0x3f,sizeof(dis));
        dis[s]=0;q.push(s);vis[s]=1;
        while(q.size()){
            int x=q.front();q.pop();vis[x]=0;
            for(int i=head[x];i;i=next[i]){
                int y=ver[i],z=edge[i];
                if(dis[y]>dis[x]+z){
                    dis[y]=dis[x]+z;
                    if(!vis[y]) vis[y]=1,q.push(y);
                }
            }
        }
    }
    int main(){
        n=read();m=read();p=min(100,(int)sqrt(n));
        for(int i=1;i<=p;i++) for(int j=1;j<=n;j++) add(id(i,j),j,0);
        for(int i=1;i<=p;i++) for(int j=1;j<=n-i;j++) add(id(i,j),id(i,j+i),1),add(id(i,j+i),id(i,j),1); 
        for(int i=1;i<=m;i++){
            int b=read()+1,sp=read();
            if(i==1) s=b;if(i==2) t=b;
            if(sp<=p) add(b,id(sp,b),0);
            else{
                for(int j=1;b+j*sp<=n;j++) add(b,b+j*sp,j);
                for(int j=1;b-j*sp>=1;j++) add(b,b-j*sp,j);
            }
        }
        spfa();printf("%d
    ",(dis[t]==0x3f3f3f3f)?-1:dis[t]);
        return 0;
    }
  • 相关阅读:
    算法题---最长公共前缀
    算法练习题---罗马数字转int
    算法练习题---原地删除数组元素
    获取当前服务的IP和端口号
    算法练习题---回文数
    Java数学表示式解析工具- jeval
    Redis的安装与部署
    Centos开机自启动redis
    Java 7 的 7 个新的 “酷” 特性
    java7新特性——使用ThreadLocalRandom产生并发随机数
  • 原文地址:https://www.cnblogs.com/xtkm/p/10830033.html
Copyright © 2011-2022 走看看