题面
题意:
定义 A ( n ) A(n) A(n)为 n n n个1构成的数字,如 A ( 3 ) = 111 A(3)=111 A(3)=111,计算有多少对 ( i , j ) (i,j) (i,j)使得 A ( i j ) % p = 0 A(i^j) \% p = 0 A(ij)%p=0。
思路:
通过枚举发现是有上面的等式是有循环节的,而且循环节是
p
−
1
p-1
p−1的因子,因此暴力枚举计算出循环节
d
d
d,接下来就是求有多少对
i
j
%
d
=
0
i^j \% d=0
ij%d=0。
将
d
d
d进行质因子分解,得
d
=
p
1
q
1
⋅
p
2
q
2
⋅
p
3
q
3
.
.
.
p
k
q
k
d={p_1}^{q_1} \cdot {p_2}^{q_2} \cdot {p_3}^{q_3} ...{p_k}^{q_k}
d=p1q1⋅p2q2⋅p3q3...pkqk
那么要使
i
j
%
d
=
0
i^j \%d = 0
ij%d=0,则
i
i
i必须为
g
=
p
1
⌈
q
1
j
⌉
⋅
p
2
⌈
q
2
j
⌉
⋅
p
3
⌈
q
3
j
⌉
.
.
.
p
k
⌈
q
k
j
⌉
g={p_1}^{\lceil {\frac{q_1}{j}} \rceil} \cdot {p_2}^{\lceil {\frac{q_2}{j}} \rceil} \cdot {p_3}^{\lceil {\frac{q_3}{j}} \rceil} ...{p_k}^{\lceil {\frac{q_k}{j}} \rceil}
g=p1⌈jq1⌉⋅p2⌈jq2⌉⋅p3⌈jq3⌉...pk⌈jqk⌉
的倍数。因此一共有
n
g
\frac{n}{g}
gn个合法的
i
i
i
由于
q
i
≤
30
q_i \leq 30
qi≤30,因此
j
j
j在
30
30
30之后和
30
30
30的答案相同,因此
j
j
j只需要枚举到
[
1
,
30
]
[1,30]
[1,30],分别计算出
g
g
g的值。
代码:
#include<bits/stdc++.h>
using namespace std;
long long qpow(long long a,long long b,long long mod){
long long ans=1;
while(b){
if(b&1) ans=(ans%mod*a%mod)%mod;
a=(a%mod*a%mod)%mod;
b>>=1;
}
return ans%mod;
}
long long qp(long long a,long long b){
long long ans=1;
while(b){
if(b&1) ans=(ans*a);
a=(a*a);
b>>=1;
}
return ans;
}
int main(){
int T;
//freopen("1.in","r",stdin);
scanf("%d",&T);
while(T--){
long long ans=0;
long long p,n,m;
vector<long long> pr;
long long re;
scanf("%lld %lld %lld",&p,&n,&m);
if(p==2||p==5){
puts("0");
continue;
}
if(p==3){
cout<<n/3*m<<endl;
continue;
}
vector<long long> all;
for(int i=2;i*i<=p-1;i++){
if((p-1)%i==0){
if(i*i==p-1) all.push_back(i);
else{
all.push_back(i);
all.push_back((p-1)/i);
}
}
}
all.push_back(p-1);
long long id;//循环节
sort(all.begin(),all.end());
for(auto v:all){//找到循环节
if((qpow(10,v,p))%p==1){
id=v;break;
}
}
vector<long long> nums;
for(int i=2;i*i<=id;i++){//质因子分解
if(id%i==0){
int num=0;
pr.push_back(i);
while(id%i==0){
id/=i;
num++;
}
nums.push_back(num);
}
}
if(id!=1){
pr.push_back(id);
nums.push_back(1);
}
long long g;
for(long long j=1;j<=min((long long)m,(long long)30);j++){
g=1;
for(int i=0;i<(int)nums.size();i++){
g*=qp(pr[i],(nums[i]+j-1)/j);
}
if(j==30) ans+=(n/g)*(m-29);
else ans+=n/g;
}
printf("%lld\n",ans);
}
return 0;
}