同余最短路学习笔记
今天闲着没事去翻图论如何建模,看到差分约束下面讲的就是我没学过的同余最短路,对此感到极为惊奇,特此来学习。
这个东西看着就很抽象,直接来看题。
P3403 跳楼机
形式化题意:给定四个正整数
显然:如果一个数
我们可以定义一个函数为
我们可以通过ZLC惊人的注意力显然发现性质:
我们可以再次用ZLC惊人的注意力显然发现性质:这玩意长得好像图论里面的四边形不等式哇哇哇!!!
所以可以掏出图论,开始连边:(
用
用
连完边之后,跑一遍最短路(迪杰斯特拉和那死了的玩意都可以),得到
对于答案,其实就是:
为什么要加
对于这道题,只要把
#include<bits/stdc++.h>
#define int long long
#define pb push_back
#define pi pair<int,int>
using namespace std;
const int N=1e5+100;
const int INF=(1ll<<63)-1;
int h,d[N],ans;
int x,y,z;
bool v[N];
vector<pi> G[N];
priority_queue<pi> q;
signed main()
{
cin>>h>>x>>y>>z;
h--;
for(int i=0;i<x;i++)
G[i].pb({(i+y)%x,y}),G[i].pb({(i+z)%x,z}),d[i]=INF;
d[0]=0;
q.push({0,0});
while(q.size())
{
int x=q.top().second;q.pop();
if(v[x]) continue;
v[x]=true;
for(auto k:G[x])
{
int y=k.first,z=k.second;
if(d[y]>d[x]+z)
d[y]=d[x]+z,q.push({-d[y],y});
}
}
for(int i=0;i<x;i++)
if(h>=d[i])
ans+=(h-d[i])/x+1;
cout<<ans<<endl;
return 0;
}
P2371 墨墨的等式
这道题就是上一道题的拓展版。上一道题只有三个数,这一道题就是
和上一道题一样的思路,只需要把
贴上正常的代码。
我没有打这个正常的代码,从你谷上找了一篇题解直接贴过来了
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 5e6 + 20;
int n;
ll w[15];
ll h,ans;
ll d[maxn];
ll l,r;
bool v[maxn];
struct N{
int to,net,va;
}a[maxn << 2];
int head[maxn];
int cnt;
void add(int x,int y,int w)
{
a[++cnt].to = y;
a[cnt].net = head[x];
a[cnt].va = w;
head[x] = cnt;
}
void SPFA()
{
memset(v,0,sizeof v);
memset(d,0x3f3f3f3f,sizeof d);
queue<int> q;
q.push(0);
v[0] = 1;
d[0] = 0;// 注意从0开始,因为基数为 0,换句话说就是,余数从0开始算
while(!q.empty())
{
int from = q.front(); q.pop();
v[from] = 0;
for(int i = head[from]; i; i = a[i].net)
{
int to = a[i].to;
int va = a[i].va;
if(d[to] > d[from] + va)
{
d[to] = d[from] + va;
if(!v[to])
{
v[to] = 1;
q.push(to);
}
}
}
}
}
int main()
{
scanf("%d%lld%lld",&n,&l,&r);
for(int i = 1; i <= n; ++i) scanf("%lld",&w[i]);
sort(w+1,w+n+1);
for(ll i = 0; i < w[1]; ++i)
{
for(int j = 2; j <= n; ++j)
{
add(i, (i+w[j]) % w[1] , w[j]);
}
}
SPFA();
for(ll i = 0; i < w[1]; ++i)
{
if(d[i] <= r) // 如果小于r ,就加答案
{
ans += (r - d[i])/w[1] + 1;
}
if(d[i] < l) // 如果小于l ,说明不合法,减去这一部分
{
ans -= (l - 1 - d[i])/w[1] + 1;
}
}
printf("%lld\n",ans);
return 0;
}
简要内容:存在简单的,不需要最短路的做法。
选择不从图论的角度去思考,而是选择Dp。更具体的说,完全背包。再具体一点说,模
具体内容可以看魏老师的
总之,对于这种做法,时间复杂度为
(ps:魏老师的代码好像没有判
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5e5+100;
int n,m;
int l,r,ans;
int a[N];
int f[N];
bool sg=false;
signed main()
{
cin>>n>>l>>r;
for(int i=1;i<=n;i++)
{
cin>>a[i];
if(!a[i])
sg=true;
}
if(sg)
{
cout<<r-l<<endl;
exit(0);
}
memset(f,0x3f,sizeof f);
f[0]=0;
sort(a+1,a+n+1);
m=a[1];
for(int i=2;i<=n;i++)
for(int j=0,lim=__gcd(m,a[i]);j<lim;j++)
for(int t=j,c=0;c<2;c+=t==j)
{
int p=(t+a[i])%m;
f[p]=min(f[p],f[t]+a[i]);
t=p;
}
for(int i=0;i<a[1];i++)
{
if(r>=f[i]) ans+=max((int)0,(r-f[i])/a[1]+1);
if(l>f[i]) ans-=max((int)0,(l-1-f[i])/a[1]+1);
}
cout<<ans<<endl;
return 0;
}
一些其他题目:
P2662 牛场围栏:一定要注意判无解啊啊啊
[ABC077D] Small Multiple:好题啊啊啊啊
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!