九校联考-DL24 凉心模拟 Day2T2 整除 (division)

本文探讨了在给定由多个质数乘积构成的n值下,求解形如n|x^m-x的方程在[1,n]区间内解的数量的方法。通过质数分解和快速幂运算,提出了一种有效的算法解决方案,并提供了详细的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

整除符号为 ∣|d∣nd|ndn 在计算机语言中可被描述为 n%d==0n\%d == 0n%d==0

现有一算式 n∣xm−xn|x^m-xnxmx,给定 nnnmmm,求 [1,n][1, n][1,n] 以内 xxx 解的个数。

解可能很大,输出取模 998244353998244353998244353

输入输出格式

输入格式

其中 nnn 的给定方式是由 ccc 个不超过 ttt 的质数的乘积给出的,cccttt

范围会在数据范围中给出。

第一行一个 ididid 表示这个数据点的标号。

多组数据,其中第二行一个整数 TTT 表示数据组数。

对于每一组数据:

第一行两个整数 cccmmm

第二行 ccc 个整数,这些整数都是质数,且两两不同,他们的乘积即为nnn

由于你可以通过输入求出 ttt,输入不再给出。

输出格式

对于每组数据输出一行,表示解的个数。

输入输出样例

输入样例#1:
0
1
2 3
2 3
输出样例#1:
6

解题分析

考虑我们每个xm≡x(mod pi)x^m\equiv x(mod\ p_i)xmx(mod pi)的解, 因为给出质数互不相等,两两都能合并成一个新的答案(类似CRTCRTCRT的操作), 所以我们算出每个质数的解再乘起来就行了。

然而暴力快速幂似乎会TLETLETLE?我们线性筛xmx^mxm即可。

代码如下:

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <algorithm>
#include <cmath>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MOD 998244353
#define ll long long
#define MX 20050
template <class T>
IN void in(T &x)
{
	x = 0; R char c = gc;
	for (; !isdigit(c); c = gc);
	for (;  isdigit(c); c = gc)
	x = (x << 1) + (x << 3) + c - 48;
}
int pri[MX], pw[MX], pcnt;
bool npr[MX];
IN int fpow(R int base, R int tim, R int mod)
{
	R int ret = 1;
	W (tim)
	{
		if(tim & 1) ret = 1ll * ret * base % mod;
		base = 1ll * base * base % mod, tim >>= 1;
	}
	return ret;
}
IN void get_pri()//先筛出质数, 降低常数
{
	for (R int i = 2; i <= 10000; ++i)
	{
		if(!npr[i]) pri[++pcnt] = i;
		for (R int j = 1; j <= pcnt; ++j)
		{
			if(pri[j] * i > 10000) break;
			npr[pri[j] * i] = true; 
			if(!(i % pri[j])) break;
		}
	}
}
IN int get(R int tm, R int pr)//筛x^m
{
	R int i, j;
	pw[1] = 1, pw[pr] = 0; R int tar;
	for (i = 2; i < pr; ++i)
	{
		if(!npr[i]) pw[i] = fpow(i, tm, pr);
		for (j = 1; pri[j] <= i; ++j)
		{
			tar = pri[j] * i;
			if(tar > pr) break;
			pw[tar] = pw[pri[j]] * pw[i] % pr;
			if(!(i % pri[j])) break;
		}
	}
	int tot = 1;
	for (i = 1; i < pr; ++i)
	if(pw[i] == i) ++tot;
	return tot;
}
IN int solve()
{
	R int res = 1, pr, ct, tm, i;
	in(ct), in(tm);
	for (i = 1; i <= ct; ++i)
	in(pr), res = 1ll * res * get(tm, pr) % MOD;
	return res;
}
int main(void)
{
	int T;
	in(T), in(T); get_pri();
	W (T--) printf("%d\n", solve());
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值