牛客多校第三场 D Big Integer(欧拉函数&计数)

牛客多校第三场 D Big Integer(欧拉函数&计数)

题目大意

给出一个函数 A ( n ) = ∑ i = 0 n − 1 1 0 i A(n)=\sum_{i=0}^{n-1}10^i A(n)=i=0n110i,现在给出一个素数p,以及范围n,m.求有多少 ( i , j ) (i,j) (i,j)满足 1 ≤ i ≤ n , 1 ≤ j ≤ m , A ( i j ) ≡ 0 ( m o d   p ) 1\le i\le n,1\le j\le m,A(i^j)\equiv0(mod\ p) 1in,1jm,A(ij)0(mod p)

解题思路

看到1111111…很容易想到POJ的那个‘The Luckiest number’即将’111111…'写成
1 0 n − 1 9 \frac{10^n-1}{9} 910n1
那么原式就可以化成
1 0 n ≡ 1 ( m o d   9 p ) 10^n\equiv 1(mod\ 9p) 10n1(mod 9p)
那么通过枚举 φ ( 9 p ) \varphi(9p) φ(9p)的因数就可以得到满足这个条件的循环节,设为g

那么只要满足 g ∣ i j g|i^j gij就是满足条件的(i,j)

首先对g进行因式分解
g = p 1 b 1 p 2 b 2 . . . p n n n g=p_1^{b_1}p_2^{b_2}...p_n^{n_n} g=p1b1p2b2...pnnn
确定一个j之后则i必须要是

d = p 1 ⌈ b 1 j ⌉ p 2 ⌈ b 2 j ⌉ . . . p n ⌈ b n j ⌉ ​ d=p_1^{\left\lceil\frac{b_1}{j}\right\rceil}p_2^{\left\lceil\frac{b_2}{j}\right\rceil}...p_n^{\left\lceil\frac{b_n}{j}\right\rceil}​ d=p1jb1p2jb2...pnjbn

的倍数,因此共有 ⌊ n d ⌋ \left\lfloor {n\over d}\right\rfloor dn各合法答案

可以发现g的所有质因子的次数都不会超过30,因此j最大到30,再增大则不会对d造成影响故直接相加即可

AC代码

#include<bits/stdc++.h>
using namespace std;
typedef __int128 LL;
LL quick_pow(LL a,LL b,LL mod)
{
    LL ans=1;
    a=a%mod;
    while(b)
    {
        if(b&1) ans=ans*a%mod;
        a=1LL*a*a%mod;
        b>>=1;
    }
    return ans;
}
LL pows(long long f,int s,int m)
{
    LL ans=1;
    int tims=s/m+(s%m!=0);
    while(tims)
    {
        if(tims&1) ans=ans*f;
        f=f*f;
        tims>>=1;
    }
    return ans;
}
vector<LL> fac;
int cnt[50];
int tor[50],tot;
int main()
{
    int t;
    scanf("%d",&t);
    int p,n,m;
    while(t--)
    {
        scanf("%d%d%d",&p,&n,&m);
        if(p%2==0||p%5==0)
        {
            puts("0");
            continue;
        }
        LL phi=6LL*(p-1);
        if(p==3) phi=18;
        LL mod=9LL*p;
        fac.clear();
        for(LL i=1;i*i<=phi;i++)
        {
            if(phi%i!=0) continue;
            fac.push_back(i);
            fac.push_back(phi/i);
        }
        sort(fac.begin(),fac.end());
        LL g=phi;
        for(auto x:fac)
        {
            if(quick_pow(10,x,mod)==1)    {g=x;break;}
        }
        LL tmp=g;
        tot=0;
        for(LL i=2;i*i<=tmp;i++)
        {
            if(g%i==0)
            {
                tor[++tot]=i;cnt[tot]=0;
                do g/=i,cnt[tot]++;
                while(g%i==0) ;
            }
        }
        if(g>1) {tor[++tot]=g;cnt[tot]=1;}
        g=tmp;
        int mx=0;
        for(int i=1;i<=tot;i++) mx=max(mx,cnt[i]);
        LL tg=1;
        long long  ans=0;
        for(LL i=1;i<=min(mx,m);i++)
        {
            tg=1;
            for(int j=1;j<=tot;j++) tg=tg*pows(tor[j],cnt[j],i);
            ans=ans+n/tg;
        }
        ans=ans+max(0,(m-mx))*(n/tg);
        printf("%lld\n",ans);
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值