题目:http://poj.org/problem?id=3539
考虑把层数分为模a剩余系。同类内可通过+若干个a走到。
不同类之间需要通过+b、+c来走到。
需要求出每一类中最小的能走到的。即最短路。
注意memset成0x3f!不要直接memset成1!
仔细一看,long long下赋1是17位,赋0x3f是19位。而h是18位。
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #define ll long long using namespace std; const int N=1e5+5; ll h,dis[N],ans; int a,b,c,head[N],xnt; bool vis[N]; struct Ed{ int next,to,w; Ed(int n=0,int t=0,int z=0):next(n),to(t),w(z) {} }ed[N<<1]; void dj() { memset(dis,0x3f,sizeof dis);dis[1%a]=1;//%a //0x3f priority_queue<pair<ll,int> > q; q.push(make_pair(-1,1%a)); while(q.size()) { int k=q.top().second;q.pop(); while(q.size()&&vis[k])k=q.top().second,q.pop(); if(vis[k])break;vis[k]=1; for(int i=head[k],v;i;i=ed[i].next) if(dis[k]+ed[i].w<dis[v=ed[i].to]) { dis[v]=dis[k]+ed[i].w;q.push(make_pair(-dis[v],v)); } } } int main() { scanf("%lld%d%d%d",&h,&a,&b,&c); for(int i=0;i<a;i++) { ed[++xnt]=Ed(head[i],(i+b)%a,b);head[i]=xnt; ed[++xnt]=Ed(head[i],(i+c)%a,c);head[i]=xnt; } dj(); for(int i=0;i<a;i++)if(dis[i]<=h)ans+=(h-dis[i])/a+1;//<=h printf("%lld",ans); return 0; }
再来个跑得快的(spfa)。
#include<iostream> #include<cstdio> #include<cstring> #define ll long long using namespace std; const int N=1e5+5; ll ans,h,dis[N]; int a,b,c,q[N<<4],hd,tl; bool vis[N]; int main() { scanf("%lld%d%d%d",&h,&a,&b,&c); if(a<b)swap(a,b);if(a<c)swap(a,c); memset(dis,0x3f,sizeof dis);dis[1%a]=1; hd=1;q[++tl]=1;vis[1%a]=1; while(hd<=tl) { int k=q[hd++];vis[k]=0; if(dis[(k+b)%a]>dis[k]+b) { dis[(k+b)%a]=dis[k]+b; if(!vis[(k+b)%a])q[++tl]=(k+b)%a,vis[(k+b)%a]=1; } if(dis[(k+c)%a]>dis[k]+c) { dis[(k+c)%a]=dis[k]+c; if(!vis[(k+c)%a])q[++tl]=(k+c)%a,vis[(k+c)%a]=1; } } for(int i=0;i<a;i++)if(dis[i]<=h)ans+=(h-dis[i])/a+1; printf("%lld",ans); return 0; }