同余最短路(总结)

Posted Harris-H

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了同余最短路(总结)相关的知识,希望对你有一定的参考价值。

同余最短路(总结)

同余最短路其实是一种优化最短路建图的方法。

通常是解决给定m个整数,求这m个整数能拼凑出多少的其他整数(这m个整数可以重复取)或给定m个整数,求这m个整数不能拼凑出的最小(最大)的整数。

时间复杂度: O ( m l o g n ) O(mlogn) O(mlogn)

P3403 跳楼机

给定 x , y , z , h x,y,z,h x,y,z,h

a x + b y + c z = k ax+by+cz=k ax+by+cz=k a , b , c ≥ 0 a,b,c\\ge 0 a,b,c0,求满足条件 k ≤ h k\\le h kh k k k有多少个。

考虑令 d i d_i di表示只通过 y , z y,z y,z可以得到的最小值,且 d i ( m o d x ) = i d_i\\pmod {x}=i di(modx)=i

从第 d i d_i di层开始,我们可以通过 x x x来增加贡献。

即: d i + x , d i + 2 x , d i + 3 x … … d_i+x,d_i+2x,d_i+3x\\dots\\dots di+x,di+2x,di+3x

因此这部分的贡献是: h − d i x \\dfrac{h-d_i}{x} xhdi

而且加上 d i d_i di 这层的贡献,就是 h − d i x + 1 \\dfrac{h-d_i}{x}+1 xhdi+1

因此最后的答案就是: ∑ i = 0 x − 1 ( h − d i x + 1 ) \\sum\\limits_{i=0}^{x-1}(\\dfrac{h-d_i}{x}+1) i=0x1xhdi+1

注意需要满足 h ≥ d i h\\ge d_i hdi 才会产生贡献。

可能有人会有疑惑,那 ( 1 , x ) (1,x) (1,x)之间的数会不会漏掉呢?答案是不会的。

如果通过 y , z y,z y,z可以得到 ( 1 , x ) (1,x) (1,x)之间的数,则这个贡献会被算到 1 1 1里去。

如果通过 y , z y,z y,z不能得到 ( 1 , x ) (1,x) (1,x)之间的数,那么显然 x , y , z x,y,z x,y,z组合更得到不到,因为 x > ( 1 , x ) x>(1,x) x>(1,x)

注意 x , y , z x,y,z x,y,z有等于1时,需要特判。

// Problem: P3403 跳楼机
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P3403
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// Date: 2021-07-08 18:22:37
// --------by Herio--------

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull; 
const int N=1e5+5,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define fi first
#define se second
#define pb emplace_back
#define SZ(a) (int)a.size()
#define ios ios::sync_with_stdio(false),cin.tie(0) 
void Print(int *a,int n){
	for(int i=1;i<n;i++)
		printf("%d ",a[i]);
	printf("%d\\n",a[n]); 
}
ll H;
int x,y,z;
ll d[N];
struct edge{
	int to,nt,w;
}e[N<<1];
int h[N],cnt;
void add(int u,int v,int w){
	e[++cnt]={v,h[u],w};h[u]=cnt;
}
int vis[N];
void spfa(){
	queue<int>q;
	mst(d,0x3f);
	vis[1]=d[1]=1;
	q.push(1);
	while(!q.empty()){
		int u=q.front();q.pop();vis[u]=0;
		for(int i=h[u];i;i=e[i].nt){
			int v=e[i].to,w=e[i].w;
			if(d[v]>d[u]+w){
				d[v]=d[u]+w;
				if(!vis[v]) q.push(v),vis[v]=1;
			}
		}
	}
}
int main(){
	scanf("%lld%d%d%d",&H,&x,&y,&z);
	if(x==1||y==1||z==1) {
		printf("%lld\\n",H);return 0;
	}
	for(int i=0;i<x;i++)  add(i,(i+y)%x,y),add(i,(i+z)%x,z);
	spfa();
	ll s=0;
	for(int i=0;i<x;i++)
		if(d[i]<=H){
			s+=(H-d[i])/x+1;
		}
	printf("%lld\\n",s);
	return 0;
}

P2371 [国家集训队]墨墨的等式

一样的题,只不过三种方式变成了 n n n种方式,而且做了个前缀和处理。

先排序,然后用最小的值作为余数,跑最短路。

注意当有 a i = 1 a_i=1 ai=1直接输出, r − l + 1 r-l+1 rl+1

0 0 0直接跳过,避免重复加边。

0 0 0开始的最短路。

// Problem: P3403 跳楼机
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P3403
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// Date: 2021-07-08 18:22:37
// --------by Herio--------

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull; 
const int N=6e6+5,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define fi first
#define se second
#define pb emplace_back
#define SZ(a) (int)a.size()
#define IOS ios::sync_with_stdio(false),cin.tie(0) 
void Print(int *a,int n){
	for(int i=1;i<n;i++)
		printf("%d ",a[i]);
	printf("%d\\n",a[n]); 
}
ll d[N];
struct edge{
	int to,nt,w;
}e[N<<1];
int h[N],cnt;
void add(int u,int v,int w){
	e[++cnt]={v,h[u],w};h[u]=cnt;
}
int vis[N];
void spfa(){
	queue<int>q;
	mst(d,0x3f);
	vis[0]=d[0]=0;
	q.push(0);
	while(!q.empty()){
		「学习笔记」同余最短路

同余最短路

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

HDU 6071 同余最短路 spfa

HDU 6071 Lazy Running (同余最短路)

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