版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Ronaldo7_ZYB/article/details/87680707
题目描述
Srwudi的家是一幢h层的摩天大楼。由于前来学习的蒟蒻越来越多,srwudi改造了一个跳楼机,使得访客可以更方便的上楼。
经过改造,srwudi的跳楼机可以采用以下四种方式移动:
- 向上移动x层;
- 向上移动y层;
- 向上移动z层;
- 回到第一层。
一个月黑风高的大中午,DJL来到了srwudi的家,现在他在srwudi家的第一层,碰巧跳楼机也在第一层。
DJL想知道,他可以乘坐跳楼机前往的楼层数。
题解
首先,我们需要思考一下两个数应该怎么解决:若数为x和y。
大体的枚举方式就是这样的。但是我们会发现,这样的枚举效率不是很高。
例如,当 时, 后的枚举就是无效的,因为会被若干个y填充。
所以最后的结果就是,求得若干个 不同的 , 。
对于三个数,思路也是一样的。求解的是 的情况。
设 表示 时, 的最小值。
这样一个式子,正好对应了一个最短路的模型。以1为起点跑最短路就能够得到相应的 值。
同理, 。
这道题其实我们,对于同余的题,从其重复性中找到一些优化求解的方法;若能够列出图论迭代式的形式,则可以用图论来求出相应的模型值。而这道题的主要难点就是根据数学模型建模,以最短路的形式辅助求解。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#include<vector>
#include<limits.h>
#include<algorithm>
#define LL long long
#define Mp make_pair
using namespace std;
LL h,x,y,z,ans=0;
LL v[200000];
LL dis[200000];
priority_queue< pair<LL,LL> >q;
vector< pair<LL,LL> >a[200000];
int main(void)
{
freopen("srwudi.in","r",stdin);
freopen("srwudi.out","w",stdout);
cin>>h>>x>>y>>z;
if (x == 1 || y == 1 || z == 1)
{
cout<<h<<endl;
return 0;
}
for (LL i=0;i<x;++i)
{
a[i].push_back(Mp((i+y)%x,y));
a[i].push_back(Mp((i+z)%x,z));
}
memset(dis,30,sizeof(dis));
dis[1]=1;
q.push(Mp(1,1));
while (q.size())
{
LL now=q.top().second;
q.pop();
if (v[now] == 1) continue;
v[now]=1;
for (LL i=0;i<a[now].size();++i)
{
LL next=a[now][i].first,val=a[now][i].second;
if (dis[now]+val < dis[next])
{
dis[next]=dis[now]+val;
q.push( Mp(-dis[next] , next) );
}
}
}
for (LL i=0;i<x;++i)
if (h-dis[i] >= 0)
ans+=(h-dis[i])/x+1;
cout<<ans<<endl;
return 0;
}