[2018.10.11 T2] 整除

暂无链接

整除

题目描述

整除符号为 ∣ | d ∣ n d|n dn 在计算机语言中可被描述为 n % d = = 0 n\%d == 0 n%d==0
现有一算式 n ∣ x m − x n|x^m − x nxmx,给定 n , m n,m nm,求 [ 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,输入不再给出。

输出格式

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

样例
样例输入

0
1
2 3
2 3

样例输出

6
另有两个样例,见下发文件。

数据范围
测试点 c ≤ c ≤ c t ≤ t ≤ t m ≤ m ≤ m T ≤ T ≤ T
1 1 1 2 2 2 1 0 3 10^3 103 2 2 2 50 50 50
2 2 2 2 2 2 1 0 3 10^3 103 1 0 9 10^9 109 50 50 50
3 3 3 2 2 2 1 0 2 10^2 102 10 10 10 10000 10000 10000
4 4 4 1 1 1 1 0 4 10^4 104 2 2 2 50 50 50
5 5 5 2 2 2 1 0 4 10^4 104 2 2 2 50 50 50
6 , 7 , 8 6,7,8 6,7,8 10 10 10 1 0 4 10^4 104 1 0 9 10^9 109 50 50 50
9 , 10 9,10 9,10 50 50 50 1 0 4 10^4 104 1 0 9 10^9 109 50 50 50

其中所有数据点都满足 1 ≤ c ≤ 50 , 1 ≤ t ≤ 1 0 4 , 1 ≤ m ≤ 1 0 9 , 1 ≤ T ≤ 10000 1 ≤ c ≤ 50,1 ≤ t ≤ 10^4,1 ≤ m ≤ 10^9,1 ≤ T ≤10000 1c50,1t104,1m109,1T10000

题解

发现对于 n ∣ x m − x   ( n = ∏ p i ) n|x^m-x\ (n=\prod p_i) nxmx (n=pi)这个式子的求解,可以化为对下面这个方程组的求解:
{ x m − x ≡ 0 m o d    p 1 x m − x ≡ 0 m o d    p 2 ⋮ x m − x ≡ 0 m o d    p c \left\{ \begin{aligned} &x^m-x\equiv 0\mod p_1\\ &x^m-x\equiv 0\mod p_2\\ &\qquad \vdots \\ &x^m-x\equiv 0\mod p_c\\ \end{aligned} \right. xmx0modp1xmx0modp2xmx0modpc

可以发现,这是一个同余方程组,那么根据中国剩余定理,整个方程组的解的个数便等于方程组中每个方程的解的个数的乘积,我们可以 O ( p ) O(p) O(p)的遍历 [ 1 , p ] [1,p] [1,p]的所有数来求解每个方程,再将解的个数乘起来得到答案,解决单词询问的复杂度为 O ( ∑ ( p i log ⁡ p i ) ) O(\sum (p_i\log p_i)) O((pilogpi))

然而丧心病狂的出题人并不满足于这样的复杂度,复杂度瓶颈在于快速幂的 log ⁡ p \log p logp,考虑我们实际上在处理函数 f ( x ) = x m m o d    p f(x)=x^m\mod p f(x)=xmmodp [ 1 , p ] [1,p] [1,p]内的值,这个函数是积性的,所以 f ( x ) f(x) f(x)在合数上的值可以线性筛出来,我们只需要在质数做快速幂,因为质数的个数约等于 p i log ⁡ p i \frac{p_i}{\log p_i} logpipi,刚好与快速幂 log ⁡ p i \log p_i logpi抵消,于是最后复杂度降为 O ( ∑ p i ) O(\sum p_i) O(pi)

代码
#include<bits/stdc++.h>
using namespace std;
const int M=1e4+5,mod=998244353;
int p[M/3],f[M],sum[M],c,m,T,ans,i,a;
bool vis[M];
int power(int x,int p,int mod){int r=1;for(;p;p>>=1,x=x*x%mod)if(p&1)r=r*x%mod;return r;}
int sie(int n,int m)
{
	int i=2,ans=2,t;
	for(p[0]=0;i<n;++i)
	{
		if(!vis[i])p[++p[0]]=i,f[i]=power(i,m,n);
		for(int j=1;j<=p[0];++j){if((t=i*p[j])>n)break;vis[t]=1;f[t]=f[i]*f[p[j]]%n;if(i%p[j]==0)break;}
		ans+=f[i]==i;
	}
	return ans;
}
void in(){scanf("%d%d",&c,&m);}
void ac(){for(ans=i=1;i<=c;++i)scanf("%d",&a),ans=1ll*ans*sie(a,m)%mod;printf("%d\n",ans);}
int main(){for(scanf("%*d%d",&T);T--;)in(),ac();}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ShadyPi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值