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\n"),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\n",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\n"),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\n",(dis[t]==0x3f3f3f3f)?-1:dis[t]); return 0; }