Luogu P3403 跳楼机|同余最短路

题意:给出跳楼机的4个操作,分别为
1.向上移动\(x\)层;

2.向上移动\(y\)层;

3.向上移动\(z\)层;

4.回到第一层。 显然,并不需要

求从第一层开始,能到达\(1\)到\(h\)中的多少层?

\(1<=h<=2^{63}-1\)

\(1<=x, y, z<=100000\)

题解:

好像可以直接\(DP\)?

布星啊,看下数据范围。

那先来推推定理?

接下来假设\(x\le y\le z\)

对于一个数\(k\),若它能到达,则\(k+x,k+2x,k+...\)(均\(\le h\))均能到达,\(y\),\(z\)同理

那我们可以选\(x\)为模数,若\(k\)可以,上面的都可以!显然可以设\(f[i]\)表示最小的可以用\(y,z\)表示出来的数。计算答案只需求\(\sum\limits^{x-1}_{i=0}(h-f[i])/x+1\),空间是质的飞跃

等等,你这根本不是递推啊,dp个鬼啊。

好吧,确实不行,但看下转移?

\(f[i+y]=f[i]+y,f[i+z]=f[i]+z\)

似曾相识有没有?

这与最短路非常相像完 全 一 致!

那就用最短路代替,从\(i->(i+y)\%x\)边权\(y\),从\(i->(i+z)\%x\)边权\(z\)。

自此,算法成型。

这就是同余系最短路

tips:应从\(1\%x\)开始跑最短路!

#include<bits/stdc++.h>
using namespace std;
long long cc,to[300100],net[300100],fr[300100],l[300100],g;
long long ans,hh,f[300100],h[300100],ha[300100],x[4];
bool vis[300100];
void addedge(long long u,long long v,long long len)
{
    cc++;
    to[cc]=v;net[cc]=fr[u];fr[u]=cc;l[cc]=len;
}
void add(long long x,long long y)
{
    g++;
    h[g]=x;ha[g]=y;
    long long fa=g/2,so=g;
    while (h[fa]>h[so]&&fa)
    {
        swap(h[fa],h[so]);
        swap(ha[fa],ha[so]);
        so=fa;fa/=2;
    }
}
long long del()
{
    long long re=ha[1];
    h[1]=h[g];ha[1]=ha[g];g--;
    long long fa=1,so=2;
    if (h[so]>h[so+1]&&so+1<=g) so++;
    while (h[fa]>h[so]&&so<=g)
    {
        swap(h[fa],h[so]);
        swap(ha[fa],ha[so]);
        fa=so;so*=2;
        if (h[so]>h[so+1]&&so+1<=g) so++;
    }
    return re;
}
void dij()
{
    for (long long i=0;i<x[0];i++)
      vis[i]=false,f[i]=9223372036854775807;
    f[1%x[0]]=1;
    add(1,1%x[0]);
    while (g)
    {
        long long x=del();
        if (vis[x]) continue;
        vis[x]=true;
        for (long long i=fr[x];i;i=net[i])
        {
            if (f[to[i]]>f[x]+l[i])
            {
                f[to[i]]=f[x]+l[i];
                add(f[to[i]],to[i]);
            }
        }
    }
}
int main()
{
    cin>>hh;
    cin>>x[0]>>x[1]>>x[2];
    sort(x+0,x+3);
    for (long long i=0;i<x[0];i++)
    {
        addedge(i,(i+x[1])%x[0],x[1]);
        addedge(i,(i+x[2])%x[0],x[2]);
    }
    dij();
    for (long long i=0;i<x[0];i++)
    {
        if (f[i]>hh) continue;
        ans+=(hh-f[i])/x[0]+1;
    }
    cout<<ans<<endl;
    return 0;
}


参考资料
【1】https://www.luogu.org/problemnew/solution/P3403

原文地址:https://www.cnblogs.com/fmj123/p/Luogu3403.html

时间: 2024-10-30 09:59:28

Luogu P3403 跳楼机|同余最短路的相关文章

同余最短路

同余最短路其实是一种优化最短路建图的方法. 通常是解决给定m个整数,求这m个整数能拼凑出多少的其他整数(这m个整数可以重复取)或给定m个整数,求这m个整数不能拼凑出的最小(最大)的整数. 我们通过一道例题来讲解. P3403 跳楼机 简化一下题意:用a,b,c(这里用a,b,c来代替x,y,z)三个数能组成几个小于h的整数.$h \leq 2^{63}-1$ 因为h过大所以直接建图显然是不行的,我们要优化空间. 我们因为这个跳的顺序是无关的,所以每个数都可以由若干次b/c再加上若干次a而形成的.

[spfa] Jzoj P4722 跳楼机

Description DJL为了避免成为一只咸鱼,来找srwudi学习压代码的技巧.Srwudi的家是一幢h层的摩天大楼.由于前来学习的蒟蒻越来越多,srwudi改造了一个跳楼机,使得访客可以更方便的上楼.经过改造,srwudi的跳楼机可以采用以下四种方式移动:1.向上移动x层:2.向上移动y层:3.向上移动z层:4.回到第一层.一个月黑风高的大中午,DJL来到了srwudi的家,现在他在srwudi家的第一层,碰巧跳楼机也在第一层.DJL想知道,他可以乘坐跳楼机前往的楼层数. Input 第

JZOJ_4722. 跳楼机 (Standard IO)

Description  DJL为了避免成为一只咸鱼,来找srwudi学习压代码的技巧.Srwudi的家是一幢h层的摩天大楼.由于前来学习的蒟蒻越来越多,srwudi改造了一个跳楼机,使得访客可以更方便的上楼.经过改造,srwudi的跳楼机可以采用以下四种方式移动:1.向上移动x层:2.向上移动y层:3.向上移动z层:4.回到第一层.一个月黑风高的大中午,DJL来到了srwudi的家,现在他在srwudi家的第一层,碰巧跳楼机也在第一层.DJL想知道,他可以乘坐跳楼机前往的楼层数. Input

【66测试20161115】【树】【DP_LIS】【SPFA】【同余最短路】【递推】【矩阵快速幂】

还有3天,今天考试又崩了.状态还没有调整过来... 第一题:小L的二叉树 勤奋又善于思考的小L接触了信息学竞赛,开始的学习十分顺利.但是,小L对数据结构的掌握实在十分渣渣.所以,小L当时卡在了二叉树. 在计算机科学中,二叉树是每个结点最多有两个子结点的有序树.通常子结点被称作“左孩子”和“右孩子”.二叉树被用作二叉搜索树和二叉堆.随后他又和他人讨论起了二叉搜索树.什么是二叉搜索树呢?二叉搜索树首先是一棵二叉树.设key[p]表示结点p上的数值.对于其中的每个结点p,若其存在左孩子lch,则key

HDU 6071 Lazy Running (同余最短路 dij)

Lazy Running Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)Total Submission(s): 1384    Accepted Submission(s): 597 Problem Description In HDU, you have to run along the campus for 24 times, or you will fail in

[Luogu3403]跳楼机

luogu 题意 其实就是给你三个数\(x,y,z\),问你能够凑出多少个\([1,h]\)之间的数. \(1\le h \le 2^{63}-1\),\(1\le x,y,z \le 10^5\) sol 用\(y,z\)凑出的在模\(x\)意义下相同的数一定是越小越好. 所以可以写一个最短路求出用\(y,z\)凑出的在模\(x\)意义下为\(i\)的最小的数,记为\(f_i\),那么模意义下为\(i\)的所有数的总贡献就是\[\lfloor\frac{h-f_i}{x}\rfloor+1\

HDU 6071 Lazy Running (同余最短路)

Lazy Running Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)Total Submission(s): 101    Accepted Submission(s): 40 Problem Description In HDU, you have to run along the campus for 24 times, or you will fail in PE

JZOJ #4722 跳楼机

题目描述: 给出h.x.y.z,求在h以内,x.y.z可以凑出多少个不同的数. (1≤h≤10^18,1≤x, y, z≤10^5.) 解题思路: 直接做显然不好做.我们考虑取n个y和m个z,然后再加上x.2 * x.3 * x...,显然地,只要对于每种取法,(ny + mz) % x 的值不同的话,就不会有重复.所以我们先求出 d[i] = c 表示通过选y和z使得和模x等于i的最小和c.然后答案就是 ∑0≤i<x (h - d[i]) / x + 1.至于怎么求d[i],可以发现 d[(i

【Luogu】P2901牛慢跑(K短路模板)

题目链接 K短路居然用A*……奇妙. 先建反图从终点(1)跑一遍最短路,再A*,用堆存当前点到终点距离+从起点到当前点距离. 每次取出终点都可以视为发现了一个新的最短路. #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #include<cctype> #include<queue> #define maxn 1020 #define m