欲望以提升热忱,毅力以磨平高山!|

XichenOC

园龄:1个月粉丝:4关注:0

2025-01-23 22:20阅读: 14评论: 0推荐: 2

同余最短路(学习笔记)

简介:

同余最短路,光是看名字就会发现与同余和最短路有关。同余最短路常用来解决的问题是:

当出现形如「给定 \(n\) 个整数,求这 \(n\) 个整数能拼凑出多少的其他整数(\(n\) 个整数可以重复取)」,以及「给定 \(n\) 个整数,求这 \(n\) 个整数不能拼凑出的最小(最大)的整数」,或者「至少要拼几次才能拼出模 \(K\)\(p\) 的数」的问题时可以使用同余最短路的方法。

同余最短路利用同余来构造一些状态,可以达到优化空间复杂度的目的。

原理:

最短路:

我们先分析最短路的原理,我们根据 \(dijkstra\) 求最短路的原理可以发现。我们是根据每一次的对点的遍历,然后不断更新 \(dis\) 数组,即为松弛操作。而一般的更新条件为:

\[dis[x]+edge(x,y)<dis[y] \]

其中的 \(edge\) 表示由 \(x\)\(y\) 的有向边的边权。那么这样更新后的最短路,显然满足一个性质,及:

\[dis[x]+edge(x,y) \geq dis[y] \]

因为若有不满住该性质的点,那一定会在求最短路时被松弛掉。

那知道这个性质后,来分析同余最短路的性质。
先引入一个问题:P3403 跳楼机

题目引入:

给定四个整数 \(x,y,z,h\),求有多少整数 \(d \in [0,h]\) 使得 \(ax+by+cz=d\) 其中的 \(a,b,c\) 都为非负整数。

称一个数合法当且仅当其可以表示成 \(ax+by+cz\) 的形式,但不一定小于等于 \(H\)

那假设一个整数 \(k=by+cx\),那很显然 \(k+x,k+2x,…,k+ax\) 都是合法的。包括 \(k\) 本身也是合法的。
那我们令函数 \(f(i)\)\(by+cz \mod x=i\) 时最小的 \(by+cz\).。
那么我们可以发现其有一个性质:

\[f(i)+y \geq f((i+y)\mod x) \]

\[f(i)+z \geq f((i+z)\mod x) \]

证明很简单,\(f(i)\) 为最小的 \(by+cz\) 使得 \(by+cz \mod x=i\),那 又因为 \(by+cz+y \mod x=i+y\) 那么 \(f(i+y)=f(i)+y\)\(i+y \geq (i+y) \mod x\),那么那么 \(f(i+y) \geq f((i+y) \mod x)\),那么就得证。

那很容易就可以发现这个式子与上面 \(dijkstra\) 松弛式子很像。那要求 \(f(i)\) 的最小值,不久相当于求 \(dis[i]\),因此我们可以用最短路的方法。先这样连边:

\[edge(i,(i+y)\mod x)=y \]

\[edge(i,(i+z)\mod x)=z \]

即:

  • \(i\)\((i+y) \mod x\) 连一条边权为 \(y\) 的边
  • \(i\)\((i+z) \mod x\) 连一条边权为 \(z\) 的边

那这样跑一遍 \(dijkstra\) 所求出的 \(dis[i]\) 就等于 \(f(i)\)

得出答案:

有了 \(f(i)\) 如何求出答案。
我们根据开局的性质 \(k=by+cz\) 那么要找的所有小于 \(h\)\(ax+by+cz\) 共有 \(\lfloor \frac{h-k}{x} \rfloor\) 个。
为了使数量尽可能大,那 \(k\) 就要最小,也就等于 \(f(i)\),那最终答案就是:

\[\sum_{i=0}^{x-1}(\lfloor \frac{h-k}{x} \rfloor+1) \]

加一是因为 \(f(i)\) 本身也合法。

完整代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10;
const int inf=9223372036854775807;
struct edge{
    int v,w;
};
struct node{
    int u,dis;
    bool operator>(const node &a)const{return dis>a.dis;}
};
priority_queue<node,vector<node>,greater<node>>q;
vector<edge>e[N];
int dis[N],vis[N];
void dijkstra(){
    dis[0]=0;
    q.push({0,0});
    while(!q.empty()){
        int u=q.top().u;
        q.pop();
        if(vis[u])continue;
        vis[u]=1;
        for(auto ed:e[u]){
            int v=ed.v,w=ed.w;
            if(dis[v]>dis[u]+w){
                dis[v]=dis[u]+w;
                q.push({v,dis[v]});
            }
        }
    }
}
signed main(){
    int h,x,y,z;
    scanf("%lld%lld%lld%lld",&h,&x,&y,&z);
    h--;
    for(int i=0;i<x;i++){
        e[i].push_back({(i+y)%x,y});
        e[i].push_back({(i+z)%x,z});
        dis[i]=inf;
    }
    dijkstra();
    int ans=0;
    for(int i=0;i<x;i++){
        if(h>=dis[i])ans+=(h-dis[i])/x+1;
    }
    printf("%lld",ans);
}

例题:

1.P2371 [国家集训队] 墨墨的等式 题解

本文作者:XichenOC

本文链接:https://www.cnblogs.com/XichenOC/p/18688713

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   XichenOC  阅读(14)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起