题解 P3403 【跳楼机】
一个比较简单的 trick。似乎网上现在只有两道题(跳楼机 和 墨墨的等式)。干脆就来写一下吧。
同余最短路
通过同余构造一些状态,状态
因此可通过此方法建图跑最短路,以此达到解决问题的效果。
【例题】跳楼机
有四种操作,分别为:
- 向上跳
x 层; - 向上跳
y 层; - 向上跳
z 层; - 回到第
1 层。
给定最高楼层
先假设
定义
不难得到两个状态:
只要我们求出
注:这里需要加一的原因是现在所处的楼层也要算一次。
现在的最主要问题是
联想到最短路,最短路的转移是:
这个转移实际上和题目要求的状态是相像的,我们只需要令
定义到这里,显然的,
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
struct Edge{
LL v,val;
Edge(){}
Edge(LL V,LL VAL){v=V,val=VAL;}
};
struct Point{
LL val;
int s;
Point(){}
Point(LL VAL,int S){val=VAL,s=S;}
bool operator < (Point another) const {return val<another.val;}
};
vector<Edge> G[100005];
LL h,d[100005];
int x,y,z;
void Dijkstra(LL s)
{
memset(d,63,sizeof d);
d[1]=1;
priority_queue<Point> Q;
Q.push(Point(1,s));
while(!Q.empty())
{
Point now=Q.top();
Q.pop();
int p=now.s;
LL val=now.val;
if(val<d[p]) continue;
for(unsigned int i=0;i<G[p].size();++i)
{
if(G[p][i].val+d[p]<d[G[p][i].v])
{
d[G[p][i].v]=G[p][i].val+d[p];
Q.push(Point(d[G[p][i].v],G[p][i].v));
}
}
}
}
int main(){
scanf("%lld %d %d %d",&h,&x,&y,&z);
if(x==1 || y==1 || z==1) return printf("%lld",h)&0;
int a[5];
a[1]=x,a[2]=y,a[3]=z;
sort(a+1,a+4);
x=a[1],y=a[2],z=a[3];
for(int i=0;i<x;++i) G[i].emplace_back(Edge((i+y)%x,y)),G[i].emplace_back(Edge((i+z)%x,z));
Dijkstra(1);
LL ans=0;
for(int i=0;i<x;++i) if(d[i]<=h) ans+=(h-d[i])/x+1;
printf("%lld",ans);
return 0;
}
【拓展】墨墨的等式
题意:
给定
与上题相差不大,唯一的变化是求有多少个
区别在于上题有
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
char buf[1<<21],*p1=buf,*p2=buf;
#define getchar() (p1==p2 && (p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
LL read()
{
LL x=0,f=1;
char c=getchar();
while(c<'0' || c>'9')
{
if(c=='-') f=-1;
c=getchar();
}
while(c>='0' && c<='9') x=(x<<1)+(x<<3)+(c^'0'),c=getchar();
return x*f;
}
void write(LL x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
struct Edge{
int v,val;
Edge(){v=val=0;}
Edge(int V,int VAL){v=V,val=VAL;}
};
struct Point{
int val,s;
Point(){val=s=0;};
Point(int VAL,int S){val=VAL,s=S;}
bool operator < (Point another) const {return val<another.val;}
};
vector<Edge> G[500005];
LL l,r,d[500005];
bool vis[500005];
int n,a[15];
void Spfa(int s)
{
memset(d,63,sizeof d);
queue<int> Q;
d[s]=0;
Q.push(s);
while(!Q.empty())
{
int now=Q.front();
Q.pop();
vis[now]=false;
for(unsigned int i=0;i<G[now].size();++i)
{
int to=G[now][i].v,val=G[now][i].val;
if(d[to]>d[now]+val)
{
d[to]=d[now]+val;
if(!vis[to]) Q.push(to),vis[to]=true;
}
}
}
}
LL query(LL upper)
{
LL ans=0;
for(LL i=0;i<a[1];++i) if(d[i]<=upper) ans+=(upper-d[i])/a[1]+1;
return ans;
}
int main(){
n=read(),l=read(),r=read();
for(LL i=1;i<=n;++i)
{
a[i]=read();
if(a[i]==1) return write(r-l+1),0;
if(!a[i]) --n,--i;
}
sort(a+1,a+1+n);
LL p=unique(a+1,a+1+n)-a-1;
n=p;
if(n==1) return write(r/a[1]-(l-1)/a[1]),0;
for(LL i=0;i<a[1];++i) for(LL j=2;j<=n;++j) G[i].emplace_back(Edge((i+a[j])%a[1],a[j]));
/*
0 2
1 0
2 1
*/
Spfa(0);
write(query(r)-query(l-1));
return 0;
}
完。