Luogu P3403 跳楼机|同余最短路

Posted fmj123

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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

以上是关于Luogu P3403 跳楼机|同余最短路的主要内容,如果未能解决你的问题,请参考以下文章

同余最短路(总结)

同余最短路

同余最短路

P2662 牛场围栏 同余最短路

「学习笔记」同余最短路

D斩杀线计算大师 同余最短路