当前位置: 首页 > news >正文

【同余最短路】P2371 [国家集训队] 墨墨的等式|省选-

本文涉及知识点

C++图论 最短路

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

题目描述

墨墨突然对等式很感兴趣,他正在研究 ∑i=1naixi=b\sum_{i=1}^n a_ix_i=bi=1naixi=b 存在非负整数解的条件,他要求你编写一个程序,给定 n,a1…n,l,rn, a_{1\dots n}, l, rn,a1n,l,r,求出有多少 b∈[l,r]b\in[l,r]b[l,r] 可以使等式存在非负整数解。

输入格式

第一行三个整数 n,l,rn,l,rn,l,r

第二行 nnn 个整数 a1…na_{1\dots n}a1n

输出格式

一行一个整数,表示有多少 b∈[l,r]b\in[l,r]b[l,r] 可以使等式存在非负整数解。

输入输出样例 #1

输入 #1

2 5 10
3 5

输出 #1

5

说明/提示

对于 20%20\%20% 的数据,n≤5n \le 5n5r≤10r \le 10r10

对于 40%40\%40% 的数据,n≤10n \le 10n10r≤106r \le 10^6r106

对于 100%100\%100% 的数据,n≤12n \le 12n120≤ai≤5×1050 \le a_i \le 5\times 10^50ai5×1051≤l≤r≤10121 \le l \le r \le 10^{12}1lr1012

同余最短路

简化版

令n =3,l = 0,r = 101210^{12}1012
式子一a0×x0+a1×x1+a1×x1+a2×x2a_0\times x_0 +a_1\times x_1 +a_1\times x_1 + a_2 \times x_2a0×x0+a1×x1+a1×x1+a2×x2
式子二a1×x1+a2×x2a_1\times x_1 + a_2 \times x_2a1×x1+a2×x2
式子一二中,aia_iai是已知值,xix_ixi是未知值。

性质一:如果式子二==b1式子二==b1式子二==b1存在自然数解,则式子一==b1+z×a0,z∈N式子一==b1+ z \times a0,z \in \N式子一==b1+z×a0zN一定存在自然数解。
性质二:如果式子二==b1式子二==b1式子二==b1存在自然数解,且 b1<a0b1 < a0b1<a0,或式子二==b1−a0式子二==b1-a0式子二==b1a0无自然数解。则任何y≡b1moda0y \equiv b1 \mod a_0yb1moda0
{式子一==y无自然数解y<b1式子一==y有自然数解其它\begin{cases} 式子一== y && 无自然数解 && y < b1 \\ 式子一==y && 有自然数解 && 其它 \\ \end{cases}{式子一==y式子一==y无自然数解有自然数解y<b1其它

利用图论求b1

有向图G,∀i∈[0,a0−1]\forall i \in [0,a_0-1]i[0,a01],都有两条出边:i→(i+a1)moda0,i→(i+a2)moda0i \rightarrow (i+a_1)\mod a_0,i \rightarrow (i+a_2)\mod a_0i(i+a1)moda0,i(i+a2)moda0。前者边权
a1a_1a1,后者边权a2a_2a2
性质三式子二≡bmoda0式子二 \equiv b \mod a_0式子二bmoda0 有正整数解 ⟺\iff 图G存在0→(bmoda0)0 \rightarrow (b \mod a0)0(bmoda0)的路径。
充分性证明:令u是第i条边的u起点,前x1x_1x1条边的终点 v=(u+a1)moda0v=(u+a_1)\mod a_0v=(u+a1)moda0,接着的x2x_2x2条边v=(u+a2)modx0v=(u+a_2) \mod x0v=(u+a2)modx0
必要性证明:如果存在合法路径则:x1=边权a1的边的数量,x2=边权a2的边的数量x1=边权a_1的边的数量,x2=边权a_2的边的数量x1=边权a1的边的数量,x2=边权a2的边的数量
结论式子二≡imoda0式子二 \equiv i \mod a_0式子二imoda0的最小式子二为0→i0 \rightarrow i0i的最短路。

实现

aia_iai升序排序,如果ai==0a_i==0ai==0删除。如果全部为0,则b只能是0。
按上述原理建边,求最短路。

代码

核心代码

#include <iostream>
#include <sstream>
#include <vector>
#include<map>
#include<unordered_map>
#include<set>
#include<unordered_set>
#include<string>
#include<algorithm>
#include<functional>
#include<queue>
#include <stack>
#include<iomanip>
#include<numeric>
#include <math.h>
#include <climits>
#include<assert.h>
#include<cstring>
#include<list>#include <bitset>
using namespace std;template<class T1, class T2>
std::istream& operator >> (std::istream& in, pair<T1, T2>& pr) {in >> pr.first >> pr.second;return in;
}template<class T1, class T2, class T3 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3>& t) {in >> get<0>(t) >> get<1>(t) >> get<2>(t);return in;
}template<class T1, class T2, class T3, class T4 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3, T4>& t) {in >> get<0>(t) >> get<1>(t) >> get<2>(t) >> get<3>(t);return in;
}template<class T1, class T2, class T3, class T4,class T5 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3, T4,T5>& t) {in >> get<0>(t) >> get<1>(t) >> get<2>(t) >> get<3>(t) >> get<4>(t);return in;
}template<class T1, class T2, class T3, class T4, class T5,class T6 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3, T4, T5,T6>& t) {in >> get<0>(t) >> get<1>(t) >> get<2>(t) >> get<3>(t) >> get<4>(t) >>get<5>(t);return in;
}template<class T = int>
vector<T> Read() {int n;cin >> n;vector<T> ret(n);for (int i = 0; i < n; i++) {cin >> ret[i];}return ret;
}
template<class T = int>
vector<T> ReadNotNum() {vector<T> ret;T tmp;while (cin >> tmp) {ret.emplace_back(tmp);if ('\n' == cin.get()) { break; }}return ret;
}template<class T = int>
vector<T> Read(int n) {vector<T> ret(n);for (int i = 0; i < n; i++) {cin >> ret[i];}return ret;
}template<int N = 1'000'000>
class COutBuff
{
public:COutBuff() {m_p = puffer;}template<class T>void write(T x) {int num[28], sp = 0;if (x < 0)*m_p++ = '-', x = -x;if (!x)*m_p++ = 48;while (x)num[++sp] = x % 10, x /= 10;while (sp)*m_p++ = num[sp--] + 48;AuotToFile();}void writestr(const char* sz) {strcpy(m_p, sz);m_p += strlen(sz);AuotToFile();}inline void write(char ch){*m_p++ = ch;AuotToFile();}inline void ToFile() {fwrite(puffer, 1, m_p - puffer, stdout);m_p = puffer;}~COutBuff() {ToFile();}
private:inline void AuotToFile() {if (m_p - puffer > N - 100) {ToFile();}}char  puffer[N], * m_p;
};template<int N = 1'000'000>
class CInBuff
{
public:inline CInBuff() {}inline CInBuff<N>& operator>>(char& ch) {FileToBuf();ch = *S++;return *this;}inline CInBuff<N>& operator>>(int& val) {FileToBuf();int x(0), f(0);while (!isdigit(*S))f |= (*S++ == '-');while (isdigit(*S))x = (x << 1) + (x << 3) + (*S++ ^ 48);val = f ? -x : x; S++;//忽略空格换行		return *this;}inline CInBuff& operator>>(long long& val) {FileToBuf();long long x(0); int f(0);while (!isdigit(*S))f |= (*S++ == '-');while (isdigit(*S))x = (x << 1) + (x << 3) + (*S++ ^ 48);val = f ? -x : x; S++;//忽略空格换行return *this;}template<class T1, class T2>inline CInBuff& operator>>(pair<T1, T2>& val) {*this >> val.first >> val.second;return *this;}template<class T1, class T2, class T3>inline CInBuff& operator>>(tuple<T1, T2, T3>& val) {*this >> get<0>(val) >> get<1>(val) >> get<2>(val);return *this;}template<class T1, class T2, class T3, class T4>inline CInBuff& operator>>(tuple<T1, T2, T3, T4>& val) {*this >> get<0>(val) >> get<1>(val) >> get<2>(val) >> get<3>(val);return *this;}template<class T = int>inline CInBuff& operator>>(vector<T>& val) {int n;*this >> n;val.resize(n);for (int i = 0; i < n; i++) {*this >> val[i];}return *this;}template<class T = int>vector<T> Read(int n) {vector<T> ret(n);for (int i = 0; i < n; i++) {*this >> ret[i];}return ret;}template<class T = int>vector<T> Read() {vector<T> ret;*this >> ret;return ret;}
private:inline void FileToBuf() {const int canRead = m_iWritePos - (S - buffer);if (canRead >= 100) { return; }if (m_bFinish) { return; }for (int i = 0; i < canRead; i++){buffer[i] = S[i];//memcpy出错			}m_iWritePos = canRead;buffer[m_iWritePos] = 0;S = buffer;int readCnt = fread(buffer + m_iWritePos, 1, N - m_iWritePos, stdin);if (readCnt <= 0) { m_bFinish = true; return; }m_iWritePos += readCnt;buffer[m_iWritePos] = 0;S = buffer;}int m_iWritePos = 0; bool m_bFinish = false;char buffer[N + 10], * S = buffer;
};//堆(优先队列)优化迪杰斯特拉算法 狄克斯特拉(Dijkstra)算法详解
typedef pair<long long, int> PAIRLLI;
class  CHeapDis
{
public:CHeapDis(int n, long long llEmpty = LLONG_MAX / 10) :m_llEmpty(llEmpty){m_vDis.assign(n, m_llEmpty);}void Cal(int start, const vector<vector<pair<int, int>>>& vNeiB){std::priority_queue<PAIRLLI, vector<PAIRLLI>, greater<PAIRLLI>> minHeap;minHeap.emplace(0, start);while (minHeap.size()){const long long llDist = minHeap.top().first;const int iCur = minHeap.top().second;minHeap.pop();if (m_llEmpty != m_vDis[iCur]){continue;}m_vDis[iCur] = llDist;for (const auto& it : vNeiB[iCur]){minHeap.emplace(llDist + it.second, it.first);}}}vector<long long> m_vDis;const long long m_llEmpty;
};class Solution {
public:long long Ans(vector<int>& as, long long left, long long r) {sort(as.begin(), as.end(), greater<>());as.erase(unique(as.begin(), as.end()), as.end());while (as.size() && (0 == as.back())) {as.pop_back();}if (as.empty()) { return 0; }const int M = as.back();vector < vector<pair<int, int>>> neiBo(M);for (int node = 0; node < M; node++) {for (const auto& w : as) {neiBo[node].emplace_back((node + w) % M, w);}}CHeapDis dis(M);dis.Cal(0, neiBo);long long ans = 0;auto f = [&](long long lr, long long bMin) {if (lr < bMin) { return 0LL; }return 1 + (lr - bMin) / M;};for (int i = 0; i < M; i++) {if (-1 == dis.m_vDis[i]) { continue; }ans += f(r, dis.m_vDis[i]);ans -= f(left - 1, dis.m_vDis[i]);}return ans;}
};
int main() {
#ifdef _DEBUGfreopen("a.in", "r", stdin);
#endif // DEBUGios::sync_with_stdio(0); cin.tie(nullptr); cout.tie(nullptr);	long long N,left,r;cin >> N >> left >> r ;	auto as = Read<int>(N);
#ifdef _DEBUGprintf("left=%I64d,r=%I64d", left,r);Out(as, "as=");//Out(fun, ",fun=");//Out(que, ",que=");
#endif // DEBUGauto res = Solution().Ans(as,left,r);cout << res;return 0;
}

单元测试

long long left, r;vector<int> as;vector<tuple<int, int, int>> edge, vCloseInfo;TEST_METHOD(TestMethod11){left = 5, r = 10,as = { 3,5 };auto res = Solution().Ans(as, left, r);AssertEx(5LL, res);}

扩展阅读

我想对大家说的话
工作中遇到的问题,可以按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。
学习算法:按章节学习《喜缺全书算法册》,大量的题目和测试用例,打包下载。重视操作
有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注
员工说:技术至上,老板不信;投资人的代表说:技术至上,老板会信。
闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛
失败+反思=成功 成功+反思=成功

视频课程

先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771
如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。

http://www.lryc.cn/news/614707.html

相关文章:

  • 在 Git 中,将本地分支的修改提交到主分支
  • 广东省省考备考(第七十天8.8)——言语、判断推理(强化训练)
  • ubuntu 22.04 使用yaml文件 修改静态ip
  • 开发板RK3568和stm32的异同:
  • Redis对象编码
  • 【Bellman-Ford】High Score
  • 荣耀秋招启动
  • Sum of Four Values(sorting and searching)
  • 两个函数 quantize() 和 dequantize() 可用于对不同的位数进行量化实验
  • 力扣-189.轮转数组
  • 优选算法 力扣 15. 三数之和 双指针降低时间复杂度 C++题解 每日一题
  • 深入解析 Seaborn:数据可视化的优雅利器
  • 自定义上传本地文件夹到七牛云
  • 虚拟机Ubuntu图形化界面root用户登录错误
  • 使用pybind11封装C++API
  • Shell、Python对比
  • 要写新项目了,运行老Django项目找找记忆先
  • C++中的继承:从基础到复杂
  • 飞算JavaAI深度解析:专为Java生态而生的智能引擎
  • 安全引导功能及ATF的启动过程(四)
  • 巧妙实现Ethercat转Profinet协议网关匹配光伏电站
  • 「ECG信号处理——(22)Pan-Tompkins Findpeak 阈值检测 差分阈值算法——三种R波检测算法对比分析」2025年8月8日
  • C语言编译流程讲解
  • 【Open3D】基础操作之三维数据结构的高效组织和管理
  • 内网穿透原理与部署实战指南:从理论到企业级应用
  • 第七章:数据持久化 —— `chrome.storage` 的记忆魔法
  • 2025 蓝桥杯C/C++国B 部分题解
  • 设计一个 Java 本地缓存组件
  • java分布式定时任务
  • 秋招笔记-8.8