同余最短路
同余最短路
与差分约束类似,都是最短路的一些神奇应用。
同余最短路可以解决类似这样的问题:
- 给定
个数,求给定值域内,用这些数(可以重复取)能够拼出多少其他数。代表题目:P3403、P2371。 - 给定
个数,求这 个整数不能拼出的最小/最大整数。代表题目:P2662。 - 给定
个数,至少要拼几次才能拼出模 余 的数。代表题目:Unknown。
P3403 跳楼机
为了方便,我们把楼层的值域从
不妨假设
就按照这两个状态建边,跑最短路,可以求出我们刚才所说的
用公式表示出来如下:
容易发现最后的时空复杂度只和
然后这题就做完了。注意细节,
#include<bits/stdc++.h>
#define int unsigned long long
using namespace std;
using pii=pair<int,int>;
constexpr int MAXN=1e5+5;
int h,x,y,z;
vector<pii>g[MAXN];
int dis[MAXN];
bool vis[MAXN];
void dijkstra(int s){
for(int i=1;i<x;++i) dis[i]=ULONG_LONG_MAX;
priority_queue<pii,vector<pii>,greater<pii>>q;
q.emplace(0,s);
while(!q.empty()){
int u=q.top().second;
q.pop();
if(vis[u]) continue;
vis[u]=1;
for(auto vv:g[u]){
int v=vv.first,w=vv.second;
if(dis[v]>dis[u]+w){
dis[v]=dis[u]+w;
q.emplace(dis[v],v);
}
}
}
}
signed main(){
cin.tie(nullptr)->sync_with_stdio(0);
cin>>h>>x>>y>>z;
--h;
for(int i=0;i<x;++i){
g[i].emplace_back((i+y)%x,y);
g[i].emplace_back((i+z)%x,z);
}
dijkstra(0);
int ans=0;
for(int i=0;i<x;++i)
if(h>=dis[i])
ans+=(h-dis[i])/x+1;
cout<<ans<<'\n';
return 0;
}
P2371 [国家集训队] 墨墨的等式
不过是上一道题的拓展。将值域从单一的
统计是同理的,加上
signed main(){
cin.tie(nullptr)->sync_with_stdio(0);
cin>>n>>l>>r>>x;
--l;
for(int i=2;i<=n;++i){
cin>>y;
for(int j=0;j<x;++j) g[j].emplace_back((j+y)%x,y);
}
dijkstra(0);
int ans=0;
for(int i=0;i<x;++i){
if(r>=dis[i]) ans+=(r-dis[i])/x+1;
if(l>=dis[i]) ans-=(l-dis[i])/x+1;
}
cout<<ans<<'\n';
return 0;
}
AT_arc084_b [ABC077D] Small Multiple
注意到任何一个正整数都可以从
建边方式为:对于所有
#include<bits/stdc++.h>
using namespace std;
constexpr int MAXN=1e5+5;
vector<pair<int,int>>g[MAXN];
int dis[MAXN];
bool vis[MAXN];
void dijkstra(int s){
memset(dis,0x3f,sizeof(dis));
dis[s]=1;
priority_queue<pair<int,int>>q;
q.emplace(1,s);
while(!q.empty()){
int u=q.top().second;
q.pop();
if(vis[u]) continue;
vis[u]=1;
for(auto vv:g[u]){
int v=vv.first,w=vv.second;
if(dis[v]>dis[u]+w){
dis[v]=dis[u]+w;
q.emplace(-dis[v],v);
}
}
}
}
int main(){
int n;
cin>>n;
for(int k=0;k<n;++k){
g[k].emplace_back((k*10)%n,0);
g[k].emplace_back((k+1)%n,1);
}
dijkstra(1);
cout<<dis[0]<<'\n';
return 0;
}
即得易见平凡,仿照上例显然。留作习题答案略,读者自证不难。
反之亦然同理,推论自然成立。略去过程 ,由上可知证毕。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】