洛谷 P3403 跳楼机 题解

题目传送门

题目大意: 1 1 1 ~ h h h 范围内,有多少个数能够拆分成 x , y , z x,y,z x,y,z 的和。

题解

同余最短路模板题。

考虑在模 x x x 意义下, y , z y,z y,z 能够组成哪些数,设 f [ i ] f[i] f[i] 表示用 y , z y,z y,z 能组成的最小的 模 x x x 等于 i i i 的数。

显然有这样的转移: f [ ( i + y )   m o d   x ] = f [ i ] + y f[(i+y)\bmod x]=f[i]+y f[(i+y)modx]=f[i]+y z z z 类似,发现这个转移很像最短路的转移: f [ y ] = f [ x ] + c o s t f[y]=f[x]+cost f[y]=f[x]+cost,并且这里我们要求的也是最小值,和最短路目的相同,所以可以用最短路算法来求出 f f f 数组。

具体来说,就是将 i i i ( i + y )   m o d   x (i+y)\bmod x (i+y)modx 连边,代价为 y y y,然后根据题意,要从 1 1 1 开始跑最短路。

求出 f [ i ] f[i] f[i] 后,在这个数的基础上加若干个 x x x,就可以得到其他的数,具体来说,能得到 ⌊ h − f [ i ] x ⌋ \lfloor \dfrac {h-f[i]} x \rfloor xhf[i] 个数,加上 f [ i ] f[i] f[i] 自己,就一共有 ⌊ h − f [ i ] x ⌋ + 1 \lfloor \dfrac {h-f[i]} x \rfloor+1 xhf[i]+1 个数。

显然,对于不同的 f [ i ] f[i] f[i],肯定不会统计到相同的数,所以不需要考虑重复统计的问题,以及由于每个数模 x x x 之后肯定对应一个 i i i,进而可以被表示成 f [ i ] + k × x f[i]+k\times x f[i]+k×x 的形式,所以每个数都会被统计到。

代码如下:

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
#define maxn 100010
#define ll long long

ll h;int a,b,c;
struct edge{int y,z,next;}e[maxn<<1];
int first[maxn],len=0;
void buildroad(int x,int y,int z){e[++len]=(edge){y,z,first[x]};first[x]=len;}
struct node{
	int x;ll d;node(int xx=0,ll dd=0):x(xx),d(dd){}
	bool operator <(const node &b)const{return d>b.d;}
};
priority_queue<node>q;
ll f[maxn];
void dij()
{
	memset(f,63,sizeof(f));
	q.push(node(1,1));f[1]=1;
	while(!q.empty())
	{
		node X=q.top();q.pop();int x=X.x;if(X.d!=f[x])continue;
		for(int i=first[x];i;i=e[i].next)
		if(f[e[i].y]>f[x]+e[i].z)f[e[i].y]=f[x]+e[i].z,q.push(node(e[i].y,f[e[i].y]));
	}
}

int main()
{
	scanf("%lld %d %d %d",&h,&a,&b,&c);
	if(a==1||b==1||c==1)return printf("%lld",h),0;
	for(int i=0;i<a;i++)buildroad(i,(i+b)%a,b),buildroad(i,(i+c)%a,c);
	dij();ll ans=0;
	for(int i=0;i<a;i++)if(f[i]<=h)ans+=(h-f[i])/a+1;
	printf("%lld",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值