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

【数论】P10580 [蓝桥杯 2024 国 A] gcd 与 lcm|普及+

本文涉及知识点

数论:质数、最大公约数、菲蜀定理

P10580 [蓝桥杯 2024 国 A] gcd 与 lcm

题目描述

给定两个数 x,yx,yx,y,求有多少种不同的长度为 nnn 的序列 (a1,a2,⋯,an)(a_1,a_2,\cdots,a_n)(a1,a2,,an),其所有元素的最大公约数为 xxx 且最小公倍数为 yyy

两个序列 (a1,a2,⋯,an)(a_1,a_2,\cdots,a_n)(a1,a2,,an)(b1,b2,⋯,bn)(b_1,b_2,\cdots,b_n)(b1,b2,,bn) 不同,是指存在至少一个位置 iii 满足 ai≠bia_i\neq b_iai=bi

由于答案可能很大,请输出答案对 998244353998\ 244\ 353998 244 353 取模后的结果。

输入格式

输入的第一行包含一个整数 QQQ 表示询问次数。

接下来 QQQ 行,每行包含三个整数 x,y,nx,y,nx,y,n 表示一组询问,相邻整数之间使用一个空格分隔。对于每个询问,保证至少存在一个满足条件的序列。

输出格式

输出 QQQ 行,每行包含一个整数,依次表示每个询问的答案。

输入输出样例 #1

输入 #1

3
3 6 2
12 144 3
233 251640 10

输出 #1

2
72
905954656

说明/提示

对于 40%40\%40% 的评测用例,n≤30n\le 30n30
对于 70%70\%70% 的评测用例,n≤5000n\le 5000n5000
对于所有评测用例,1≤Q≤1001\le Q\le 1001Q1002≤n≤1052\le n\le 10^52n1051≤x,y≤1091\le x,y\le 10^91x,y109

数论

本题⟺gcd(a)==1,lcm(a)=z=y/x\iff gcd(a)==1,lcm(a)=z=y/xgcd(a)==1,lcm(a)=z=y/x
对z进行质因数分解,z=Πpiciz=\Pi p_i^{c_i}z=Πpici
显然各pip_ipi是独立,子方案数相乘便是总方案数。
至少一个数不包括pip_ipi否则不互质,枚举a[j]是第一个不包括质因数pi的数a[j]是第一个不包括质因数p_i的数a[j]是第一个不包括质因数pi的数
则:
ak,k<ja_k,k<jak,k<j取值范围[1,c_i];k>j,取值范围[0,c_i]$不会超限。
cij(ci+1)n−j−1{c_i}^j(c_i+1)^{n-j-1}cij(ci+1)nj1
要扣掉所有aia_iai都不取cic_ici的方案数:
ci−1j(ci)n−j−1{c_i-1}^j(c_i)^{n-j-1}ci1j(ci)nj1
时间复杂度:O(nlognlogn)
质因数数量和快速指数幂时间复杂度是logn。
超时,预处理好ci,ci+1c_i,c_i+1ci,ci+1的幂。时间复杂度:降为O(nlogn)

代码

核心代码

#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<array>#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, class T6, class T7 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3, T4,T5,T6,T7>& t) {in >> get<0>(t) >> get<1>(t) >> get<2>(t) >> get<3>(t) >> get<4>(t) >> get<5>(t) >> get<6>(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();while (('\r' == *S) || ('\n' == *S) || (' ' == *S)) { S++; }//忽略空格和回车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;
};template<long long MOD = 1000000007, class T1 = int, class T2 = long long>
class C1097Int
{
public:C1097Int(T1 iData = 0) :m_iData(iData% MOD){}C1097Int(T2 llData) :m_iData(llData% MOD) {}C1097Int  operator+(const C1097Int& o)const{return C1097Int(((T2)m_iData + o.m_iData) % MOD);}C1097Int& operator+=(const C1097Int& o){m_iData = ((T2)m_iData + o.m_iData) % MOD;return *this;}C1097Int& operator-=(const C1097Int& o){m_iData = ((T2)MOD + m_iData - o.m_iData) % MOD;return *this;}C1097Int  operator-(const C1097Int& o)const{return C1097Int(((T2)MOD + m_iData - o.m_iData) % MOD);}C1097Int  operator*(const C1097Int& o)const{return((T2)m_iData * o.m_iData) % MOD;}C1097Int& operator*=(const C1097Int& o){m_iData = ((T2)m_iData * o.m_iData) % MOD;return *this;}C1097Int  operator/(const C1097Int& o)const{return *this * o.PowNegative1();}C1097Int& operator/=(const C1097Int& o){*this *= o.PowNegative1();return *this;}bool operator==(const C1097Int& o)const{return m_iData == o.m_iData;}bool operator<(const C1097Int& o)const{return m_iData < o.m_iData;}C1097Int pow(T2 n)const{C1097Int iRet = (T1)1, iCur = *this;while (n){if (n & 1){iRet *= iCur;}iCur *= iCur;n >>= 1;}return iRet;}C1097Int PowNegative1()const{return pow(MOD - 2);}T1 ToInt()const{return ((T2)m_iData + MOD) % MOD;}
private:T1 m_iData = 0;;
};template<class T = int>
class CUniqueFactorization
{
public:CUniqueFactorization(T iPrime, int cnt) {m_data.emplace_back(iPrime, cnt);}CUniqueFactorization(vector<T> primes = {}, vector<int> cnts = {}) {for (int i = 0; i < primes.size(); i++) {m_data.emplace_back(primes[i], cnts[i]);}}CUniqueFactorization operator+ (const CUniqueFactorization& o)const {return Add(o, true);}CUniqueFactorization Add(const CUniqueFactorization& o, bool bIgornZero = false)const {CUniqueFactorization ret;int i = 0, j = 0;while ((i < m_data.size()) && (j < o.m_data.size())) {if (m_data[i].first == o.m_data[j].first) {int cnt = m_data[i].second + o.m_data[j].second;if ((0 != cnt) || !bIgornZero){ret.m_data.emplace_back(m_data[i].first, cnt);}i++, j++;}else if (m_data[i].first < o.m_data[j].first) {ret.m_data.emplace_back(m_data[i]);i++;}else {ret.m_data.emplace_back(o.m_data[j]);j++;}}ret.m_data.insert(ret.m_data.end(), m_data.begin() + i, m_data.end());ret.m_data.insert(ret.m_data.end(), o.m_data.begin() + j, o.m_data.end());return ret;}CUniqueFactorization negation()const {CUniqueFactorization ret;ret = *this;for (auto& [i, cnt] : ret.m_data) {cnt *= -1;}return ret;}CUniqueFactorization GetValue(const CUniqueFactorization& o)const {CUniqueFactorization ret;for (const auto& [pri, cnt] : m_data) {ret.m_data.emplace_back(pri, 0);}return ret + o;};pair<T, T> Union()const {long long ll1 = 1, ll2 = 1;for (auto [pri, cnt] : m_data) {auto& ll = (cnt >= 0) ? ll1 : ll2;for (int j = 0; j < abs(cnt); j++) {ll *= pri;}//可以用快速指数幂加速}return { ll1,ll2 };}vector<pair<T, int>> m_data;
};class CCreatePrime {
public:CCreatePrime(int iMax) :m_isPrime(iMax + 1, true){m_isPrime[0] = m_isPrime[1] = false;for (int i = 2; i <= iMax; i++){if (m_isPrime[i]){m_vPrime.emplace_back(i);}for (const auto& n : m_vPrime){if ((long long)n * i > iMax) { break; }m_isPrime[n * i] = false;if (0 == i % n) { break; }}}}vector<int> m_vPrime;vector<bool> m_isPrime;
};
template<class T = int>
class CUniqueFactorizationFactory {
public:CUniqueFactorizationFactory(T iMax) :m_cc(sqrt(iMax) + 2), m_vPrime(m_cc.m_vPrime) {}CUniqueFactorization<T> Factorization(T x) {CUniqueFactorization<T> ret;for (const auto& iPre : m_vPrime) {int cnt = 0;while (0 == x % iPre) {cnt++;x /= iPre;}if (cnt > 0) {ret.m_data.emplace_back(iPre, cnt);}if (iPre * iPre > x) { break; }}if (x > 1) {ret.m_data.emplace_back(x, 1);}return ret;}const vector<int>& m_vPrime;
protected:CCreatePrime m_cc;
};typedef	C1097Int<998244353> BI;
class Solution {public:int Ans(int x,int y,int n) {BI ans(1);const int z = y / x;auto  uf = CUniqueFactorizationFactory(z).Factorization(z);for (const auto& [p, c] : uf.m_data) {BI cur = 0;vector<BI> cs(n, 1), c1s(n, 1);for (int i = 1; i < n; i++) {cs[i] = cs[i - 1] * c;c1s[i] = c1s[i - 1] * (c + 1);}BI c1 = 1, c2 = 1;for (int j = 0; j < n; j++) {cur += c1* c1s[n - j - 1];cur -= c2 * cs[n - j - 1];c1 *= c;c2 *= (c - 1);}ans *= cur;}return ans.ToInt();}};int main() {
#ifdef _DEBUGfreopen("a.in", "r", stdin);
#endif // DEBUG	ios::sync_with_stdio(0); cin.tie(nullptr);//CInBuff<> in; COutBuff<10'000'000> ob;int T,x,y,n;cin >> T;for (int t = 0; t < T; t++){cin >> x >> y >> n ;
#ifdef _DEBUG	//printf("N=%d", N);//Out(not1, ",not1=");//Out(ope, ",ope=");//Out(str2, ",str2=");//Out(que, ",ope=");
#endif // DEBUG		auto res = Solution().Ans(x,y,n);cout << res << "\n";}}

单元测试

	TEST_METHOD(TestMethod11){			auto res = Solution().Ans(3,6,2);AssertEx(2, res);}TEST_METHOD(TestMethod12){auto res = Solution().Ans(12, 144 ,3);AssertEx(72, res);}TEST_METHOD(TestMethod13){auto res = Solution().Ans(233 ,251640 ,10);AssertEx(905954656, 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.xdnf.cn/news/20535.html

相关文章:

  • MapStruct详解
  • Linux RCU (Read-Copy-Update) 机制深度分析
  • leetcode 912 排序数组(快速排序)
  • 【CV】Opencv图像处理——①几何变换 (1)
  • 神马 M66S+ 282T矿机参数详解:SHA-256算法与Hydro冷却技术
  • 贪心算法应用:食品生产线排序问题详解
  • 继承详解(c++)
  • langchain源码概览
  • Java全栈开发面试实录:从基础到实战的深度解析
  • 【牛客刷题-剑指Offer】BM18 二维数组中的查找:一题四解,从暴力到最优
  • Python元组:不可变但灵活的数据容器
  • LwIP入门实战 — 3 以太网外设 (ETH)
  • 什么是JQ
  • solidity函数篇2
  • Netty从0到1系列之EventLoop
  • 魅族 Note 16 解锁 BL 及 Root 官方刷机包下载Flyme 12.0.1.5A 型号 M521Q
  • 基于SVN搭建企业内部知识库系统实践
  • 试用电子实验记录本ELN的经验之谈
  • 【算法】92.翻转链表Ⅱ--通俗讲解
  • Vue 3项目中引用ECharts并设计多种图表组件的实现方案
  • 行政区划编码树形题解
  • 09_多态
  • `IntersectionObserver`延迟加载不在首屏的自动播放视频/图片/埋点/
  • Boost电路:稳态和小信号分析
  • Linux匿名管道和命名管道以及共享内存
  • C++并发编程指南 递归锁 介绍
  • Kimi K2-0905 256K 上下文 API 状态管理优化教程
  • 2.虚拟内存:分页、分段、页面置换算法
  • 分享一个基于Python+大数据的房地产一手房成交数据关联分析与可视化系统,基于机器学习的深圳房产价格走势分析与预测系统
  • Embedding上限在哪里?- On the Theoretical Limitations of Embedding-Based Retrieval