版权声明:大佬您能赏脸,蒟蒻倍感荣幸,还请联系我让我好好膜拜。 https://blog.csdn.net/ShadyPi/article/details/83047995
暂无链接
整除
题目描述
整除符号为
∣,
d∣n 在计算机语言中可被描述为
n%d==0。
现有一算式
n∣xm−x,给定
n,m,求
[1,n]以内
x解的个数。
解可能很大,输出取模
998244353。
格式
输入格式
其中
n的给定方式是由
c个不超过
t的质数的乘积给出的,
c和
t的范围会在数据范围中给出。
第一行一个
id表示这个数据点的标号。
多组数据,其中第二行一个整数
T表示数据组数。
对于每一组数据:
第一行两个整数
c和
m。
第二行
c个整数,这些整数都是质数,且两两不同,他们的乘积即为
n。
由于你可以通过输入求出
t,输入不再给出。
输出格式
对于每组数据输出一行,表示解的个数。
样例
样例输入
0
1
2 3
2 3
样例输出
6
另有两个样例,见下发文件。
数据范围
测试点 |
c≤ |
t≤ |
m≤ |
T≤ |
1 |
2 |
103 |
2 |
50 |
2 |
2 |
103 |
109 |
50 |
3 |
2 |
102 |
10 |
10000 |
4 |
1 |
104 |
2 |
50 |
5 |
2 |
104 |
2 |
50 |
6,7,8 |
10 |
104 |
109 |
50 |
9,10 |
50 |
104 |
109 |
50 |
其中所有数据点都满足
1≤c≤50,1≤t≤104,1≤m≤109,1≤T≤10000。
题解
发现对于
n∣xm−x (n=∏pi)这个式子的求解,可以化为对下面这个方程组的求解:
⎩⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎧xm−x≡0modp1xm−x≡0modp2⋮xm−x≡0modpc
可以发现,这是一个同余方程组,那么根据中国剩余定理,整个方程组的解的个数便等于方程组中每个方程的解的个数的乘积,我们可以
O(p)的遍历
[1,p]的所有数来求解每个方程,再将解的个数乘起来得到答案,解决单词询问的复杂度为
O(∑(pilogpi))。
然而丧心病狂的出题人并不满足于这样的复杂度,复杂度瓶颈在于快速幂的
logp,考虑我们实际上在处理函数
f(x)=xmmodp在
[1,p]内的值,这个函数是积性的,所以
f(x)在合数上的值可以线性筛出来,我们只需要在质数做快速幂,因为质数的个数约等于
logpipi,刚好与快速幂
logpi抵消,于是最后复杂度降为
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();}