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

题目描述

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

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

解可能很大,输出取模 998244353 998244353 998244353

输入输出格式

输入格式

其中 n n n 的给定方式是由 c c c 个不超过 t t t 的质数的乘积给出的, c c c t t t

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

第一行一个 i d id id 表示这个数据点的标号。

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

对于每一组数据:

第一行两个整数 c c c m m m

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

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

输出格式

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

输入输出样例

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

解题分析

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

然而暴力快速幂似乎会 T L E TLE TLE?我们线性筛 x m x^m xm即可。

代码如下:

#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());
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值