【luogu3403】跳楼机 [同余最短路]

本文深入探讨了跳楼机算法的实现,通过巧妙地利用同余最短路思想,解决了DJL在srwudi家中使用特定移动方式到达不同楼层的问题。文章详细介绍了如何通过SPFA算法计算可达楼层数量,为解决类似问题提供了有效的算法思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

P3403 跳楼机

P3403 跳楼机

经过改造,srwudi的跳楼机可以采用以下四种方式移动:

向上移动x层;向上移动y层;向上移动z层;回到第一层。

一个月黑风高的大中午,DJL来到了srwudi的家,现在他在srwudi家的第一层,碰巧跳楼机也在第一层。DJL想知道,他可以乘坐跳楼机前往的楼层数。

yyb:先只考虑只用\(y,z\)两种移动方式,它们一定能够到达一些楼层,
那么这些楼层再只用\(x\)拓展就能够计算答案。
那么我们这样子计算答案,设\(dis[i]\)表示可以到达\(mod\ x=i\)楼层的最小值,

很巧妙!同余最短路

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=100000+10,M=100000+10,inf=0x3f3f3f3f;
int x,y,z;
ll n,ans=0;
template <class t>void rd(t &x){
    x=0;int w=0;char ch=0;
    while(!isdigit(ch)) w|=ch=='-',ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    x=w?-x:x;
}

int head[N],tot=0;
struct edge{int v,w,nxt;}e[M<<2];
void add(int u,int v,int w){
    e[++tot]=(edge){v,w,head[u]},head[u]=tot;
}

queue<int>q;bool vis[N];
ll dis[N];
void spfa(){
    memset(dis,inf,sizeof(dis));
    memset(vis,0,sizeof(vis));
    q.push(1),vis[1]=1,dis[1]=1;
    while(!q.empty()){
        int u=q.front();q.pop(),vis[u]=0;
        for(int i=head[u],v,w;i;i=e[i].nxt)
        if(dis[v=e[i].v]>dis[u]+(w=e[i].w)){
            dis[v]=dis[u]+w;
            if(!vis[v]) q.push(v),vis[v]=1;
        }
    }
}

int main(){
//  freopen("in.txt","r",stdin);
    rd(n),rd(x),rd(y),rd(z);
    if(n==1||x==1||y==1||z==1) return printf("%lld",n),0;
    for(int i=0;i<x;++i) add(i,(i+y)%x,y),add(i,(i+z)%x,z);
    spfa();
    for(int i=0;i<x;++i)
        if(dis[i]<=n) ans+=(n-dis[i])/x+1;
    printf("%lld",ans);
    return 0;
}

[国家集训队]墨墨的等式

和跳楼机那题是一样的==

#include<bits/stdc++.h>
using namespace std;
#define Max(x,y) ((x)>(y)?(x):(y))
#define Min(x,y) ((x)<(y)?(x):(y))
#define ll long long
const int N=12+10,M=500000+10,inf=0x3f3f3f3f;
int n,a[N];
ll b1,b2,ans=0;
template <class t>void rd(t &x){
    x=0;int w=0;char ch=0;
    while(!isdigit(ch)) w|=ch=='-',ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    x=w?-x:x;
}

int head[M],tot=0;
struct edge{int v,w,nxt;}e[M*20];
void add(int u,int v,int w){
    e[++tot]=(edge){v,w,head[u]},head[u]=tot;
}

queue<int>q;bool vis[M];
ll dis[M];
void spfa(){
    memset(dis,inf,sizeof(dis));
    memset(vis,0,sizeof(vis));
    q.push(0),vis[0]=1,dis[0]=0;
    while(!q.empty()){
        int u=q.front();q.pop(),vis[u]=0;
        for(int i=head[u],v,w;i;i=e[i].nxt)
        if(dis[v=e[i].v]>dis[u]+(w=e[i].w)){
            dis[v]=dis[u]+w;
            if(!vis[v]) q.push(v),vis[v]=1;
        }
    }
}

int main(){
    freopen("in.txt","r",stdin);
    rd(n),rd(b1),rd(b2);
    for(int i=1;i<=n;++i) rd(a[i]);
    sort(a+1,a+n+1);
    for(int i=0;i<a[1];++i)
        for(int j=2;j<=n;++j) add(i,(i+a[j])%a[1],a[j]);
    spfa();
    for(int i=0;i<a[1];++i){
        if(dis[i]<=b1-1) ans-=(b1-1-dis[i])/a[1]+1;
        if(dis[i]<=b2) ans+=(b2-dis[i])/a[1]+1;
    }
    printf("%lld",ans);
    return 0;
}

转载于:https://www.cnblogs.com/lxyyyy/p/11529326.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值