【简单数论题】整除

Description

  • 给定 n,mn,mn,m, 求 [1,n][1,n][1,n] 内满足 n∣xm−xn|x^m-xnxmxxxx 的个数。
  • m≤109m\le 10^9m109
  • n=∏i=1cpin=\prod_{i=1}^c p_in=i=1cpipip_ipi 均为质数且互不相同, pi≤10000,c≤50p_i\le 10000,c\le50pi10000,c50
  • 每个测试点数据组数 ≤10000\le 1000010000
  • 时间限制 5s5s5s,空间限制 256MB256MB256MB

Solution

  • 非常有意思的一道题。
  • 感觉让我这个初学数论的菜鸡学到了很多东西。

算法一

  • 原方程等价于 x(xm−1−1)≡0(mod n)x(x^{m-1}-1)\equiv 0(mod~n)x(xm11)0(mod n)
  • xxx 的取值范围可以对应到 [0,n)[0,n)[0,n),这样我们只需要判断模 nnn 意义下的解的个数即可。
  • 这个同余方程成立,等价于对于每个 iii x(xm−1−1)≡0(mod pi)x(x^{m-1}-1)\equiv 0(mod~p_i)x(xm11)0(mod pi)
  • 由于 pip_ipi 是质数,我们可以知道上面这个方程又等价于 x≡0(mod pi)x\equiv 0(mod~p_i)x0(mod pi)xm−1≡1(mod pi)x^{m-1}\equiv 1(mod~p_i)xm11(mod pi)
  • 上面两个方程解出来的 xxx 均是 pip_ipi剩余类
  • 那么我们就取模 ppp 的值作为方程的解。
  • 显然两个方程解出的 xxx 不会有同一个。
  • 所以方程 x(xm−1−1)≡0(mod pi)x(x^{m-1}-1)\equiv 0(mod~p_i)x(xm11)0(mod pi) 的解数就是上面两个方程的解数之和。
  • 我们假设 AiA_iAi 表示我们对方程 x(xm−1−1)≡0(mod pi)x(x^{m-1}-1)\equiv 0(mod~p_i)x(xm11)0(mod pi) 解出的所有 xxxpip_ipi 的值组成的集合。
  • 那么,因为 pip_ipi 互不相同,根据中国剩余定理,我们对于每个同余方程组:

∀i∈[1,c],x≡ai(mod pi),ai∈Ai \forall i\in[1,c],x\equiv a_i(mod~p_i),a_i\in A_i i[1,c]xai(mod pi)aiAi

  • 我们都能得到模 nnn 意义下的唯一解。
  • 所以解数就是所有集合 AiA_iAi 的大小的乘积
  • 我们回到刚刚的两个方程:x≡0(mod pi)x\equiv 0(mod~p_i)x0(mod pi)xm−1≡1(mod pi)x^{m-1}\equiv 1(mod~p_i)xm11(mod pi)
  • 对于方程1,我们只需要取 x=0x=0x=0 一个解。
  • 对于方程2,暴力枚举验证的每次时间复杂度是 O(pilog⁡m)O(p_i\log m)O(pilogm) 的。
  • 但是时间复杂度为 O(T∑i=1cpilog⁡m)O(T\sum_{i=1}^c p_i\log m)O(Ti=1cpilogm),并不能通过本题。

算法二

  • 现在的问题就是如何快速求出形如xn≡1(mod p),p是质数x^n \equiv 1(mod~p),p是质数xn1(mod p)p
  • 的方程在模 ppp 意义下的解的数量。
  • 我们定义数论函数 f(x)=xnf(x)=x^nf(x)=xn
  • 显然 f(x)f(x)f(x) 是完全积性函数。
  • 我们可以使用线性筛线性筛出,对于每个质数暴力快速幂计算。
  • [1,p)[1,p)[1,p) 内质数个数是 O(pln⁡p)O(\frac{p}{\ln p})O(lnpp) 的,然后对于每个质数 O(log⁡n)O(\log n)O(logn) 计算,总的时间复杂度可以认为是 O(p)O(p)O(p),然后线性筛部分是 O(p)O(p)O(p) 的。
  • 因此我们可以每次 O(p)O(p)O(p) 处理出来这个函数在 [0,p)[0,p)[0,p) 上的所有值对 ppp 取模的值,并 O(p)O(p)O(p) 求出解的数量,实现 O(T∑i=1cpi)O(T\sum_{i=1}^c p_i)O(Ti=1cpi) 的时间复杂度。
#include <cmath>
#include <cstdio>
#include <cctype>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>

template <class T>
inline void read(T &x)
{
	static char ch; 
	while (!isdigit(ch = getchar())); 
	x = ch - '0'; 
	while (isdigit(ch = getchar()))
		x = x * 10 + ch - '0'; 
}

const int MaxN = 1e4 + 5; 

int id, T, c, m, n; 

inline int qpow(int a, int b, const int &mod)
{
	int res = 1; 
	for (; b; b >>= 1, a = 1LL * a * a % mod)
		if (b & 1)
			res = 1LL * res * a % mod; 
	return res; 
}

//the number of x (x^m=p)(x in [0,p))
inline int solve(const int &m, const int &p)
{
	static bool sie[MaxN]; 
	static int pri[MaxN], f[MaxN], cnt; 
	
	int res = 1; 
	
	memset(sie, 0, sizeof(sie)); 
	cnt = 0; 
	
	f[1] = 1; 
	for (int i = 2; i < p; ++i)
	{
		if (!sie[i])
		{
			pri[++cnt] = i; 
			f[i] = qpow(i, m, p); 
		}
		for (int j = 1; j <= m; ++j)
		{
			int x = i * pri[j]; 
			if (x >= p) break; 
			sie[x] = true; 
			
			f[x] = 1LL * f[i] * f[pri[j]] % p; 
			if (i % pri[j] == 0)
				break; 
		}
		if (f[i] == 1)
			++res; 
	}
	return res; 
}

int main()
{
	freopen("division.in", "r", stdin); 
	freopen("division.out", "w", stdout); 
	
	#define mod 998244353
	
	read(id), read(T); 
	while (T--)
	{
		read(c), read(m); 
		
		int ans = 1; 
		
		int x; 
		for (int i = 1; i <= c; ++i)
		{
			read(x); 
			ans = 1LL * ans * (solve(m - 1, x) + 1) % mod; 
		}
		
		printf("%d\n", ans); 
	}
	
	fclose(stdin); 
	fclose(stdout); 
	return 0; 
}

算法三

  • 实际上这道题有很优秀的做法。
  • 此算法来自某个神仙考场上猜的结论。
  • 方程 xn≡1(mod p),p是质数x^n \equiv 1(mod~p),p是质数xn1(mod p)p 在模 ppp 意义下的解的数量为 gcd(n,p−1)gcd(n,p-1)gcd(n,p1)
  • 我们来证明一下这个显而易见的结论。
  • 证明:
    • xxx 的取值范围为 [1,p)[1,p)[1,p)
    • 这个方程形如一个 NNN 次剩余的形式。
    • 我们令 ggg 表示 ppp 的一个原根。
    • 根据原根的性质 ,集合 {x∣x=gk&VeryThinSpace;mod&VeryThinSpace;p,k∈[1,p),k∈Z}\{x|x=g^k\bmod p,k\in [1,p),k\in \mathbb Z\}{xx=gkmodp,k[1,p),kZ} 和集合 {1,2,…,p−1}\{1,2,\dots,p-1\}{1,2,,p1} 相等。
    • x=gyx=g^yx=gyy∈[1,p)y\in[1,p)y[1,p))。
    • 所以原方程可以表示为 gn×y≡g0(mod p)g^{n\times y}\equiv g^0(mod~p)gn×yg0(mod p)
    • 根据 gp−1=1g^{p-1}=1gp1=1,我们得到 n×y≡0(mod (p−1))n\times y\equiv 0(mod~(p-1))n×y0(mod (p1))
    • 写成同余方程的形式即 (p−1)x+ny=0(p-1)x+ny=0(p1)x+ny=0
    • 显然我们可以取特解 x=y=0x=y=0x=y=0,得到 yyy 的通解为 k⋅p−1(p−1,n)(k∈Z)k·\frac{p-1}{(p-1,n)}(k\in \mathbb Z)k(p1,n)p1kZ
    • 我们代到 yyy 的取值范围中即有 1≤k⋅p−1(p−1,n)≤p−11\le k·\frac{p-1}{(p-1,n)}\le p-11k(p1,n)p1p1
    • 解出来 kkk 可以取 [1,(p−1,n)][1,(p-1,n)][1,(p1,n)] 内的任意整数。
    • 证毕。
  • 那么对于每个质数就可以 O(log p)O(log~p)O(log p) 的时间复杂度求出 gcdgcdgcd 算答案了。
  • 答案即为 ∏i=1c(gcd(m−1,p−1)+1)\prod_{i=1}^c(gcd(m-1,p-1)+1)i=1c(gcd(m1,p1)+1)
  • 可以轻松通过本题。
#include <cmath>
#include <cstdio>
#include <cctype>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>

const int mod = 998244353; 

int id, T, c, m, n; 

int main()
{
	freopen("division.in", "r", stdin); 
	freopen("division.out", "w", stdout); 
	
	scanf("%d%d", &id, &T); 
	while (T--)
	{
		scanf("%d%d", &c, &m); 
		
		int ans = 1; 
		
		int x; 
		for (int i = 1; i <= c; ++i)
		{
			scanf("%d", &x); 
			ans = 1LL * ans * (1 + std::__gcd(m - 1, x - 1)) % mod; 
		}
		
		std::cout << ans << std::endl; 
	}
	
	fclose(stdin); 
	fclose(stdout); 
	return 0; 
}
第一阶段:搜索算法核心突破(3.25-3.28 | 4天) 3.25-3.26:DFS基础与剪枝 学习内容:回溯模板、排列/子集生成、剪枝技巧(可行性/最优性剪枝) 真练习: 全排列问(第七届《凑算式》变种) 迷宫路径计数(二维矩阵搜索) 3.27-3.28:BFS与连通性问 学习内容:队列实现BFS、层序遍历、连通块计数 真练习: 第七届《剪邮票》(DFS验证5格连通性) 岛屿数量问(连通块计数) 第二阶段:动态规划专(3.29-4.1 | 4天) 3.29-3.30:线性DP与递推 学习内容:爬楼梯模型、打家劫舍变种、递推公式设计 真练习: 第七届《煤球数目》(直接递推) 第十四届《接龙数列》(字符串状态转移)3.31-4.1:背包DP与字符串DP 学习内容:01背包模板、滚动数组优化、最长公共子序列 真练习: 第十二届《砝码称重》(01背包变种) 编辑距离问(字符串DP) 第三阶段:数论+贪心强化(4.2-4.4 | 3天) 4.2:质数与GCD 学习内容:埃氏筛法、欧几里得算法、因数分解 真练习:第十二届《货物摆放》(求因数组合) 4.3:快速幂与模运算 学习内容:快速幂模板、逆元计算(选学) 真练习:大数取模问(如计算10^{18} \mod 710 18 mod7) 4.4:贪心策略 学习内容:区间调度、相邻交换策略 真练习:第四届《翻硬币》(贪心翻转)、第九届《乘积最大》 第四阶段:数据结构+图论(4.5-4.7 | 3天)4.5:并查集与优先队列 学习内容:路径压缩、按秩合并、Dijkstra堆优化 真练习:第十二届《城邦》(并查集预处理) 4.6:栈与图论基础 学习内容:表达式计算、Dijkstra最短路径 真练习:第十二届《路径》(Dijkstra模板) 4.7:拓扑排序与最小生成树 学习内容:Kahn算法、Kruskal实现 真练习:第十四届《飞机降落》(拓扑排序思想)第五阶段:二分+综合复习(4.8-4.10 | 3天) 4.8:二分查找与答案 学习内容:边界处理、最大值最小化问练习:第十二届《直线》(排序去重+二分优化) 4.9-4.10:全真模拟与查漏补缺 任务:限时刷近3年真(重点做搜索、DP、数论) 错复盘:整理易错代码片段(如DFS状态遗漏、DP初始化错误)时间完全不够 我3.25-3.29都没把DFS要学习的内容学完也还没加以联系,这份安排太紧凑了,难以让我真的深入理解这些算法,只能明白个模板,帮我再做一份学习计划吧,可以删减些比赛出现可能性相对较低的算法或者算法中的学习内容,以求留下广东省十六届以前蓝桥杯c赛道b组出现频率最高能覆盖尽量多考试类型的算法,帮我再精简筛选一下,然后按照在2025年广东省蓝桥杯c赛道b组可能出现的频率的顺序帮我重新安排一下学习内容,以助我拿下奖项。从3.30开始给我从新安排一下,现在学了DFS的迷宫,全排列,回溯模板,但还没加以真练习
最新发布
03-30
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值