题目链接:
题意:有这样一些数,全部由1组成,例如:1,11,111,1111,…
定义A(n)为第n大的数,计算: ∑ i = 1 n ∑ j = 1 m [ A ( i j ) ≡ 0 ( m o d p ) ] \sum_{i=1}^{n}\sum_{j=1}^{m}[A(i^j)\equiv 0 ( mod p)] ∑i=1n∑j=1m[A(ij)≡0(modp)]
我们设: A ( n ) = 1 0 n − 1 9 A(n)=\frac{10^n-1}{9} A(n)=910n−1
即:
考虑p与9互质。
( 1 0 n − 1 ) ∗ i n v 9 ≡ 0 ( m o d p ) (10^n-1)*inv9 \equiv 0(modp) (10n−1)∗inv9≡0(modp)
因为inv9不为0,故:
1 0 n ≡ 1 ( m o d p ) 10^n\equiv 1(mod p) 10n≡1(modp)
由费马小定理,可得n为p-1,也就是存在一个循环节d,使得只要满足 d ∣ i j d|i^j d∣ij,此 i j i^j ij就满足条件。
但这里的循环节不一定是p-1,它可能更小,我们可以通过打表看出。或者我们可以这样想,假设存在p-1的因子d,满足 1 0 d ≡ 1 ( m o d p ) 10^d\equiv1(mod p) 10d≡1(modp),此时d就为更小的循环节,那么现在我们只需先找到p-1的循环节。
循环找出来后,就变成求:
∑ i = 1 n ∑ j = 1 m d ∣ i j \begin{aligned}\sum_{i=1}^{n}\sum_{j=1}^{m}d|i^j\end{aligned} i=1∑nj=1∑md∣ij
下面参考官方题解:
设 m a = m a x ( k 1 , k 2 , . . . , k l ) ma=max(k_1,k_2,...,k_l) ma=max(k1,k2,...,kl),那么当 j > = m a j>=ma j>=ma时,g此时都不会再改变,此时就有 n g ∗ ( m − m a ) \frac{n}{g}*(m-ma) gn∗(m−ma)。
再者,当p为2,5时, 1 0 n ≡ 0 ( m o d p ) 10^n\equiv 0(mod p) 10n≡0(modp),说明不存在这样的 A ( i j ) A(i^j) A(ij)
当p=3时,因为p与9并不互质,故题目就变成了求:
∑ i = 1 n ∑ j = 1 m [ A ( i j ) m o d 3 = = 0 ] \sum_{i=1}^{n}\sum_{j=1}^{m}[A(i^j)mod 3==0] ∑i=1n∑j=1m[A(ij)mod3==0],那么显然就变成A(i^j)数字中,各位数相加是否为3的倍数,我们先不考虑j,即有 n 3 \frac{n}{3} 3n这么多个i,那么最后结果就为 n 3 ∗ m \frac{n}{3}*m 3n∗m
#include
using namespace std;
typedef long long LL;
LL mod;
LL fast(LL x,LL y)
{
LL ans=1;
while(y)
{
if(y&1) ans=ans*x%mod;
x=x*x%mod;
y>>=1;
}
return ans;
}
pair pri[2000];
int main()
{
int ncase;
scanf("%d",&ncase);
while(ncase--)
{
LL p,n,m;
scanf("%lld%lld%lld",&p,&n,&m);
mod=p;
if(p==2||p==5){
puts("0");
continue;
}
if(p==3){
printf("%lld\n",n/3*m);
continue;
}
LL mi=p-1,x=p-1;
///找出循环节mi
for(LL i=2;i*i<=x;i++)
{
if(x%i==0){
if(fast(10,i)==1){
mi=min(mi,i);
}
if(fast(10,x/i)==1) mi=min(mi,x/i);
}
}
// printf("mi=%lld\n",mi);
int cnt=0;
x=mi;
LL ma=0;
for(LL i=2;i*i<=x;i++)///质因子分解循环节mi
{
if(x%i==0){
pri[++cnt].second=0;
pri[cnt].first=i;
while(x%i==0){
pri[cnt].second++;
x/=i;
}
ma=max(ma,pri[cnt].second);
}
}
if(x>1){
pri[++cnt].first=x;
pri[cnt].second=1;
ma=max(ma,pri[cnt].second);
}
LL ans=0;
LL g=1;
for(LL j=1;j<=min(m,ma);j++){ ///枚举j
g=1;
for(int i=1;i<=cnt;i++){
g=g*fast(pri[i].first,ceil(1.0*pri[i].second/j));
}
ans+=n/g;
}
if(m>ma){
ans+=(n/g)*(m-ma);
}
printf("%lld\n",ans);
}
return 0;
}