三句话题面:
1.定义y|x,表示y整除x
2.且f(x)=y,表示x的正因子个数为y。(其实是$ \tau(x)=y
或
者
或者
或者\sigma_0(x)=y$)
计算同时满足两个条件的x,输出他们的累加和(取模),如果有无限多个输出-1。
一道非常毒瘤的题目。我们可以注意到将x和y进行质因数分解,通过打表和仔细观察,我们可以得到一个神奇的结论:如果y某个质因数指数>1,则x一定为-1(特殊的,4不是-1),然后我们利用公式 τ ( x ) = Π ( e i + 1 ) \tau(x)=\Pi(ei+1) τ(x)=Π(ei+1) ei为分解质因数后的第i个质数的指数。考虑用dfs遍历全排列就可以了。当然dp才可以防止被毒瘤数据卡住。(不同的质数太多)。
然而数据有一点小小的掉节操,1018次方,迫使你认为欧拉筛过不了。(然而有信仰的rym大佬只筛了107以内的数,,然后就过了。。。)
正确做法是使用Miller_Rabin算法判质数,Pollard_Rho算法分解因数。关于伪质数天敌carmichael,我们可以暴力判3 5 7 11 13 17 41的倍数,或者打表(只有255个数)。哦,还有特判1。
code:
#include<bits/stdc++.h>
#define N 20005
#define LL long long
using namespace std;
#define INF 2e18
#define TIMES 15
LL f[N],n,mo,T;
LL divsor[100];
int dcnt=0;
LL dmi=INF;
LL GetRandom(LL n)
{
LL num = (((unsigned LL)rand() + 100000007)*rand())%n;
return num+1;
}
LL Mod_Mul(LL a,LL b,LL mod)
{
LL msum=0;
while(b)
{
if(b&1) msum = (msum+a)%mod;
b>>=1;
a = (a+a)%mod;
}
return msum;
}
LL Quk_Mul(LL a,LL b,LL mod)
{
LL qsum=1;
while(b)
{
if(b&1) qsum=Mod_Mul(qsum,a,mod);
b>>=1;
a=Mod_Mul(a,a,mod);
}
return qsum;
}
bool Miller_Rabin(LL n)
{
if(n==2||n==3||n==5||n==7||n==11||n==13||n==17||n==41) return true;
if(n==1||n%2==0||n%3==0||n%5==0||n%7==0||n%11==0||n%41==0||n%17==0) return false;
if (n%13==0) return false;
int div2=0;
LL tn=n-1;
while( !(tn&1) )
{
div2++;
tn>>=1;//脱平方根
}
for(int tt=0;tt<TIMES;tt++)
{
LL x=GetRandom(n-1); //随机得到[1,n-1]
if(x==1) continue;
x=Quk_Mul(x,tn,n);
LL pre=x;//平凡平方根,最小根可以为p-1,其余必须为1
for(int j=0;j<div2;j++)
{
x = Mod_Mul(x, x, n);
if(x==1&&pre!=1&&pre!=n-1) return false;
pre=x;
}
if(x!=1) return false;
}
return true;
}
LL gcd(LL a,LL b)
{
if(b==0) return a;
return gcd(b,a%b);
}
LL pollard_rho(LL dn,LL dc)
{
LL x,y,d,i=1,k=2;
x=GetRandom(dn-1);
y=x;
while(1)
{
i++;
x=(Mod_Mul(x,x,dn)+dc)%dn;
d=gcd(y-x,dn);
if(1<d&&d<dn)
return d;
if(y==x) return dn;
if(i==k)
{
y=x;
k<<=1;
}
}
}
void Divide(LL dn,int dk){
if(dn==1)return ;
if(Miller_Rabin(dn)==true){
divsor[dcnt++]=dn;
dmi=min(dmi,dn);
return ;
}
LL dtmp=dn;
while(dtmp>=dn)dtmp=pollard_rho(dtmp,dk--);
Divide(dtmp,dk);
Divide(dn/dtmp,dk);
}
void solve(LL x,LL mo){
if(x==1){printf("1\n");return ;}
if(x==4) {printf("%lld",8%mo);return ;}
memset(divsor,0,sizeof divsor); dcnt=0;
if(Miller_Rabin(n))divsor[++dcnt]=n;
else{dcnt++;Divide(x,251);}
while(divsor[dcnt]==0)dcnt--;
sort(divsor+1,divsor+dcnt+1);
for(int i=1;i<=dcnt;i++)
if(divsor[i]==divsor[i-1]){
printf("-1\n");return ;
}
f[0]=1;
for(int i=1;i<(1<<dcnt);i++){
int s=0;f[i]=0;
for(int j=i;j;j-=(j&-j),s++);
for(int j=1;j<=dcnt;j++)
if(i&(1<<(j-1))) f[i]=(f[i]+Mod_Mul(f[i-(1<<(j-1))],Quk_Mul(divsor[s],divsor[j]-1,mo),mo))%mo;
}
printf("%lld\n",f[(1<<dcnt)-1]);
return ;
}
int main(){
freopen("sum.in","r",stdin);
freopen("sum.out","w",stdout);
srand(unsigned(time(0)));
scanf("%lld",&T);
while(T--){
scanf("%lld%lld",&n,&mo);
solve(n,mo);
}
return 0;
}