暂无链接
整除
题目描述
整除符号为∣|∣,d∣nd|nd∣n 在计算机语言中可被描述为 n%d==0n\%d == 0n%d==0。
现有一算式n∣xm−xn|x^m − xn∣xm−x,给定n,mn,mn,m,求[1,n][1, n][1,n]以内xxx解的个数。
解可能很大,输出取模998244353998244353998244353。
格式
输入格式
其中nnn的给定方式是由ccc个不超过ttt的质数的乘积给出的,ccc和ttt的范围会在数据范围中给出。
第一行一个ididid表示这个数据点的标号。
多组数据,其中第二行一个整数TTT表示数据组数。
对于每一组数据:
第一行两个整数ccc和mmm。
第二行ccc个整数,这些整数都是质数,且两两不同,他们的乘积即为nnn。
由于你可以通过输入求出ttt,输入不再给出。
输出格式
对于每组数据输出一行,表示解的个数。
样例
样例输入
0
1
2 3
2 3
样例输出
6
另有两个样例,见下发文件。
数据范围
测试点 | c≤c ≤c≤ | t≤t ≤t≤ | m≤m ≤m≤ | T≤T ≤T≤ |
---|---|---|---|---|
111 | 222 | 10310^3103 | 222 | 505050 |
222 | 222 | 10310^3103 | 10910^9109 | 505050 |
333 | 222 | 10210^2102 | 101010 | 100001000010000 |
444 | 111 | 10410^4104 | 222 | 505050 |
555 | 222 | 10410^4104 | 222 | 505050 |
6,7,86,7,86,7,8 | 101010 | 10410^4104 | 10910^9109 | 505050 |
9,109,109,10 | 505050 | 10410^4104 | 10910^9109 | 505050 |
其中所有数据点都满足1≤c≤50,1≤t≤104,1≤m≤109,1≤T≤100001 ≤ c ≤ 50,1 ≤ t ≤ 10^4,1 ≤ m ≤ 10^9,1 ≤ T ≤100001≤c≤50,1≤t≤104,1≤m≤109,1≤T≤10000。
题解
发现对于n∣xm−x (n=∏pi)n|x^m-x\ (n=\prod p_i)n∣xm−x (n=∏pi)这个式子的求解,可以化为对下面这个方程组的求解:
{xm−x≡0mod  p1xm−x≡0mod  p2⋮xm−x≡0mod  pc
\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.
⎩⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎧xm−x≡0modp1xm−x≡0modp2⋮xm−x≡0modpc
可以发现,这是一个同余方程组,那么根据中国剩余定理,整个方程组的解的个数便等于方程组中每个方程的解的个数的乘积,我们可以O(p)O(p)O(p)的遍历[1,p][1,p][1,p]的所有数来求解每个方程,再将解的个数乘起来得到答案,解决单词询问的复杂度为O(∑(pilogpi))O(\sum (p_i\log p_i))O(∑(pilogpi))。
然而丧心病狂的出题人并不满足于这样的复杂度,复杂度瓶颈在于快速幂的logp\log plogp,考虑我们实际上在处理函数f(x)=xmmod  pf(x)=x^m\mod pf(x)=xmmodp在[1,p][1,p][1,p]内的值,这个函数是积性的,所以f(x)f(x)f(x)在合数上的值可以线性筛出来,我们只需要在质数做快速幂,因为质数的个数约等于pilogpi\frac{p_i}{\log p_i}logpipi,刚好与快速幂logpi\log p_ilogpi抵消,于是最后复杂度降为O(∑pi)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();}