D—Big Integer (质因子分解)2019牛客多校

题目链接:
题意:有这样一些数,全部由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=1nj=1m[A(ij)0(modp)]

我们设: A ( n ) = 1 0 n − 1 9 A(n)=\frac{10^n-1}{9} A(n)=910n1
即:
考虑p与9互质。
( 1 0 n − 1 ) ∗ i n v 9 ≡ 0 ( m o d p ) (10^n-1)*inv9 \equiv 0(modp) (10n1)inv90(modp)
因为inv9不为0,故:
1 0 n ≡ 1 ( m o d p ) 10^n\equiv 1(mod p) 10n1(modp)

由费马小定理,可得n为p-1,也就是存在一个循环节d,使得只要满足 d ∣ i j d|i^j dij,此 i j i^j ij就满足条件。
但这里的循环节不一定是p-1,它可能更小,我们可以通过打表看出。或者我们可以这样想,假设存在p-1的因子d,满足 1 0 d ≡ 1 ( m o d p ) 10^d\equiv1(mod p) 10d1(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=1nj=1mdij

下面参考官方题解:

D—Big Integer (质因子分解)2019牛客多校_第1张图片

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(mma)
再者,当p为2,5时, 1 0 n ≡ 0 ( m o d p ) 10^n\equiv 0(mod p) 10n0(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=1nj=1m[A(ij)mod3==0],那么显然就变成A(i^j)数字中,各位数相加是否为3的倍数,我们先不考虑j,即有 n 3 \frac{n}{3} 3n这么多个i,那么最后结果就为 n 3 ∗ m \frac{n}{3}*m 3nm


#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;

}

你可能感兴趣的:(数论)