题目大意:给一个序列A(x),A(i)代表由i个一组成的十进制数,A(3)=111.A(5)=11111等,给定素数p,求所有能满足A(i^j)%p==0的(i,j)有多少对。
解:
首先一个显然的结论:A(p-1)%p==0,p是质数。
我们要统计(i,j)有多少对等价于找出x从小到大第一个使得A(x)%p==0的x,然后找多少对(i,j)满足x<=i^j。
首先一个结论,对于p>=5,p是素数,那么A(p-1)%p==0.
这意味着我们只需要从p-1的因子中找那个x就可以了,要探寻的范围小了很多。
于是因数分解,质因数分解,再从小到大暴力枚举因数,找到x(因为A(x)=(10^x-1)/9,所以直接处理逆元再快速幂就可以了)
找到了这样的x,怎么计数对数呢
还是暴力枚举,不过需要几个技巧:
1.x=p1^q1*p2^q2*……*pn^qn,开1/j次根号,相当于对qi/j向上取整,所以枚举j,对于每个j值算出来的temp,ans+=n/temp;
2.找出最大的qi,记为mx,j的枚举次数应该小于min(mx,m),因为当j大于mx时,pow(qi,1/j)向上取整等于1,不必再往后枚举了,直接计算。
#include
#include
#include
#include
using namespace std;
typedef long long ll;
typedef int INT;
#define int \
long long
const int maxn=50050;
//const ll MOD=1e9+7;
ll divv[maxn];
ll prime[maxn];
ll p,n,m;
int sum[maxn];
int cnt,tot;
void divide(ll x){
cnt=0;
for(ll i=1;i*i<=x;i++){
if(x%i==0){
divv[++cnt]=i;
if(i!=x/i) divv[++cnt]=x/i;
}
}
}
void get_prime(ll x){
tot=0;
memset(sum,0,sizeof(sum));
for(ll i=2;i*i<=x;i++){
if(x%i==0){
prime[++tot]=i;
while(x%i==0){
x/=i;sum[tot]++;
}
}
}
if(x>1){
prime[++tot]=x;sum[tot]=1;
}
}
ll quickpow(ll a,ll b,ll MOD){
ll c=1;
while(b){
if(b&1) c=c*a%MOD;
a=a*a%MOD;b>>=1;
}
return c;
}
ll inv(ll a,ll MOD){
return quickpow(a,MOD-2,MOD);
}
void solve(){
int T;
scanf("%d",&T);
while(T--){
//memset()
scanf("%lld %lld %lld",&p,&n,&m);
if(p==2||p==5) printf("0\n");
else if(p==3) printf("%lld\n",n/3*m);
else{
//if(p==3) p++;
divide(p-1);
//for(int i=0;i<=cnt;i++) printf("divv[%d]=%lld\n",i,divv[i]);
sort(divv+1,divv+cnt+1);
ll res=0;
for(int i=2;i<=cnt;i++){
//printf("i=%d,qp=%lld\n",i,((quickpow(10,divv[i],p)-1+p)%p*inv(9,p)%p)%p);
if((quickpow(10,divv[i],p)-1+p)%p*inv(9,p)%p==0){
res=divv[i];break;
}
}
get_prime(res);
ll ans=0;
int mx=-1;
for (int i=1;i<=tot;i++) mx=max(mx,sum[i]);
for(int j=1;j<=min(m,mx);j++){
ll temp=1;
for(int i=1;i<=tot;i++){
ll s=(sum[i]+j-1)/j;
for (int k=0;kmx) {
ll ret=1;
for (int j=1;j<=tot;j++) ret=ret*prime[j];
ans+=(m-mx)*(n/ret);
}
printf("%lld\n",ans);
}
}
}
INT main(){
solve();
return 0;
}