同余最短路

前言

打GYM时遇见了一题同余最短路,队友写过,今天来补下知识点

P3403 跳楼机

题目链接:跳楼机
大意:给定 x , y , z x,y,z x,y,z,求能组合成多少个小于h的数。
数据范围: 1 ≤ x , y , z ≤ 1 e 5 1\le x,y,z\le1e5 1x,y,z1e5
题解:同余最短路
AC代码:

#include<bits/stdc++.h>
#define int long long
#define ld long double
#define ll long long
using namespace std;
template<class T>
void read(T& x)
{
	T res = 0, f = 1; char c = getchar();
	while (!isdigit(c)) {
		if (c == '-')f = -1; c = getchar();
	}
	while (isdigit(c)) {
		res = (res << 3) + (res << 1) + c - '0'; c = getchar();
	}
	x = res * f;
}
const ll N = 200000 + 10;
const int mod = 1e9 + 7;
int a[5],h,dis[N];
bool in[N];
signed main()
{
	//ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
	freopen("test.in", "r", stdin);
#endif // ONLINE_JUDGE
	read(h); h--;
	for (int i = 1; i <= 3; i++)read(a[i]);
	sort(a + 1, a + 1 + 3);
	memset(dis, 0x3f, sizeof(dis));
	queue<int>pls;
	pls.push(0); dis[0] = 0; in[0] = 1;
	while (pls.size())
	{
		int f = pls.front(); pls.pop(); in[f] = 0;
		for (int i = 2; i <= 3; i++)
		{
			int t = (f + a[i]) % a[1];
			if (dis[t] > dis[f] + a[i])
			{
				dis[t] = dis[f] + a[i];
				if (!in[t])pls.push(t), in[t] = 1;
			}
		}
	}
	ll ans = 0;
	for (int i = 0; i < a[1]; i++)
	{
		if (h < dis[i])continue;
		ans += (h - dis[i]) / a[1] + 1;
	}
	printf("%lld\n", ans);
	return 0;
}

GYM100753 M-Sums

题目链接:M-Sums
题目大意:给定n个数 a 1 − n a_{1-n} a1n q q q次询问,询问 a a a数组是否能组合成 k k k
数据范围: 1 ≤ a i ≤ 50000 , 1 ≤ n ≤ 50000 , k ≤ 1 e 18 , q ≤ 100000 1\le a_i\le 50000,1\le n\le 50000,k\le 1e18,q\le 100000 1ai50000,1n50000,k1e18,q100000
题解:同余最短路
AC代码:

#include<bits/stdc++.h>
#define ld long double
#define ll long long
using namespace std;
template<class T>
void read(T& x)
{
	T res = 0, f = 1; char c = getchar();
	while (!isdigit(c)) {
		if (c == '-')f = -1; c = getchar();
	}
	while (isdigit(c)) {
		res = (res << 3) + (res << 1) + c - '0'; c = getchar();
	}
	x = res * f;
}
const ll N = 200000 + 10;
const int mod = 1e9 + 7;
int a[N], dis[N],n,vis[N];
int main()
{
	//ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
	freopen("test.in", "r", stdin);
#endif // ONLINE_JUDGE
	read(n);
	for (int i = 1; i <= n; i++)read(a[i]);
	sort(a + 1, a + 1 + n);
	memset(dis, 0x3f, sizeof(dis));
	dis[0] = 0;
	queue<int>pls;
	pls.push(0); vis[0] = 1;
	while (pls.size())
	{
		int f = pls.front(); pls.pop(); vis[f] = 0;
		for (int i = 1; i <= n; i++)
		{
			int to = (f + a[i]) % a[1];
			if (dis[to] > dis[f] + a[i])
			{
				dis[to] = dis[f] + a[i];
				if (!vis[to])
					pls.push(to), vis[to] = 1;
			}
		}
	}
	int q; read(q);
	while (q--)
	{
		int x; read(x);
		printf("%s\n", x >= dis[x % a[1]] ? "TAK" : "NIE");
	}
	return 0;
}

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

题目链接:P2371 [国家集训队]墨墨的等式
大意:在这里插入图片描述
数据范围: 1 ≤ n ≤ 12 , 0 ≤ a i ≤ 5 ∗ 1 0 5 , 1 ≤ l , r ≤ 1 e 12 1\le n\le 12,0\le a_i\le5*10^5,1\le l,r\le 1e12 1n12,0ai5105,1l,r1e12
题解:同余最短路。
AC代码:

#include<bits/stdc++.h>
#define int long long
#define ld long double
#define ll long long
using namespace std;
template<class T>
void read(T& x)
{
	T res = 0, f = 1; char c = getchar();
	while (!isdigit(c)) {
		if (c == '-')f = -1; c = getchar();
	}
	while (isdigit(c)) {
		res = (res << 3) + (res << 1) + c - '0'; c = getchar();
	}
	x = res * f;
}
const ll N = 500000 + 10;
const int mod = 1e9 + 7;
int a[20],n,l,r,dis[N];
bool in[N];
ll query(int x)
{
	ll ans = 0;
	for (int i = 0; i < a[1]; i++)
	{
		if (x < dis[i])continue;
		ans += (x - dis[i]) / a[1] + 1;
	}
	return ans;
}
signed main()
{
	//ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
	freopen("test.in", "r", stdin);
#endif // ONLINE_JUDGE
	read(n), read(l), read(r);
	for (int i = 1; i <= n; i++)read(a[i]);
	sort(a + 1, a + 1 + n);
	memset(dis, 0x3f, sizeof(dis));
	queue<int>pls;
	pls.push(0); dis[0] = 0; in[0] = 1;
	while (pls.size())
	{
		int f = pls.front(); pls.pop(); in[f] = 0;
		for (int i = 2; i <= n; i++)
		{
			int t = (f + a[i]) % a[1];
			if (dis[t] > dis[f] + a[i])
			{
				dis[t] = dis[f] + a[i];
				if (!in[t])pls.push(t), in[t] = 1;
			}
		}
	}
	printf("%lld\n", query(r)-query(l-1));
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值