[2018.10.11 T2] 整除

版权声明:大佬您能赏脸,蒟蒻倍感荣幸,还请联系我让我好好膜拜。 https://blog.csdn.net/ShadyPi/article/details/83047995

暂无链接

整除

题目描述

整除符号为 | d n d|n 在计算机语言中可被描述为 n % d = = 0 n\%d == 0
现有一算式 n x m x n|x^m − x ,给定 n m n,m ,求 [ 1 , n ] [1, n] 以内 x x 解的个数。
解可能很大,输出取模 998244353 998244353

格式
输入格式

其中 n n 的给定方式是由 c c 个不超过 t t 的质数的乘积给出的, c c t t 的范围会在数据范围中给出。
第一行一个 i d id 表示这个数据点的标号。
多组数据,其中第二行一个整数 T T 表示数据组数。
对于每一组数据:
第一行两个整数 c c m m
第二行 c c 个整数,这些整数都是质数,且两两不同,他们的乘积即为 n n
由于你可以通过输入求出 t t ,输入不再给出。

输出格式

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

样例
样例输入

0
1
2 3
2 3

样例输出

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

数据范围
测试点 c c ≤ t t ≤ m m ≤ T T ≤
1 1 2 2 1 0 3 10^3 2 2 50 50
2 2 2 2 1 0 3 10^3 1 0 9 10^9 50 50
3 3 2 2 1 0 2 10^2 10 10 10000 10000
4 4 1 1 1 0 4 10^4 2 2 50 50
5 5 2 2 1 0 4 10^4 2 2 50 50
6 , 7 , 8 6,7,8 10 10 1 0 4 10^4 1 0 9 10^9 50 50
9 , 10 9,10 50 50 1 0 4 10^4 1 0 9 10^9 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

题解

发现对于 n x m x   ( n = p i ) n|x^m-x\ (n=\prod p_i) 这个式子的求解,可以化为对下面这个方程组的求解:
{ 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.

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

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

代码
#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();}

猜你喜欢

转载自blog.csdn.net/ShadyPi/article/details/83047995
T2