2019牛客暑期多校训练营(第三场) D-Big Integer - BenFromHRBUST

2019牛客暑期多校训练营(第三场) D-Big Integer

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

For little pupils, a very large number usually means an integer with many many digits. Let’s define a class of big integers which consists only of the digit one(11⋯1). The first few integers in this class are 1,11,111,1111⋯. Denote A(n) as the n-th smallest integer in this class. To make it even larger, we consider integers in the form of A(a^ b). Now, given a prime number p, how many pairs (i,j) are there such that 1 ≤ i ≤ n,1 ≤ j ≤m, A(i^j) ≡0(mod p)

输入描述:

The input contains multiple cases. The first line of the input contains a single integer T (1≤T≤100), the number of cases.
For each case, the input consists of a single line, which contains 3 positive integers p, n, m (p, n, m ≤ 10 e 9) .

输出描述:

Print the answer, a single integer, in one separate line for each case.

-----------------------------------------------------------分隔线----------------------------------------------------------------

题意

1 ≤ i ≤ n, 1 ≤ j ≤ m 有多少种情况满足i ^ j个1能被p整除。

思路

原式:A(i ^ j) % p==0(记i ^ j为n)
易知,A(n)等价于(10 ^ n-1)/9,即为n个1。可化简为:((10^n-1)/9)%p ==0。
因为p为质数,所以9与p互质,故((10^n-1)*inv9)%p ==0。
因为inv9!=0,故(10^n-1)%p ==0,即(10 ^ n)≡1(mod p)。
根据费马小定理,10与p互质,故10 ^ phi( p)≡1(mod p)。
因为p为素数,phi(p )==p-1,所以10 ^ (p-1)≡1(mod p)。
所以最小循环节d必定是p-1的因数。然后直接O(sqrt(p-1))暴力找到d。
(最后一点懒得写了,直接贴牛客的题解了)
在这里插入图片描述
------------------------------------分割线---------------------------------------------------------------------------------------

代码

#include <bits/stdc++.h>
#define min(x,y) (x>y?y:x)
#define __bug(x) cout<<"---test:"<<x<<endl

using namespace std;

typedef long long ll;

const ll MOD=1e9+7;

struct S
{
    ll num;
    ll times;
}pr[55];

ll quick_pow(ll a,ll b,ll p)
{
    ll ret=1;
    a%=p;
    while(b)
    {
        if(b&1)
            ret=ret*a%p;
        a=a*a%p;
        b>>=1;
    }
    return ret%p;
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        ll p,n,m;
        scanf("%lld%lld%lld",&p,&n,&m);
        if(p==2||p==5)
        {
            printf("0\n");
            continue;
        }
        if(p==3)
        {
            printf("%lld\n",n/3*m);
            continue;
        }
        ll d=p-1;
        for(int i=2;i*i<=p-1;i++)
        {
            if((p-1)%i==0)
            {
                if(quick_pow(10,i,p)==1)
                {
                    d=min(d,i);
                }
                if(quick_pow(10,(p-1)/i,p)==1)
                {
                    d=min(d,(p-1)/i);
                }
            }
        }
//        __bug(d);
        int cnt=0;
        ll dd=d;
        ll maxn=0;
        for(int i=2;i*i<=d;i++)
        {
            if(dd%i==0)
            {
                pr[cnt].num=i;
                pr[cnt].times=0;
                while(dd%i==0)
                {
                    dd/=i;
                    pr[cnt].times++;
                }
                maxn=max(maxn,pr[cnt].times);
                cnt++;
//                __bug(maxn);
            }
        }
        ll g=1;
        if(dd>1)
        {
            pr[cnt].num=dd;
            pr[cnt].times=1;
            maxn=max(pr[cnt].times,maxn);
            cnt++;
//            __bug(maxn);
        }
//        for(int i=0;i<cnt;i++)
//        {
//            cout<<"test:"<<pr[i].num<<' '<<pr[i].times<<endl;
//        }
        ll ans=0;
        for(int i=1;i<=min(maxn,m);i++)
        {
            g=1;
            for(int j=0;j<cnt;j++)
            {
                g=g*quick_pow(pr[j].num,ceil((double)pr[j].times/i),MOD);
            }
            ans+=n/g;
//            cout<<"test:"<<i<<' '<<g<<endl;
        }
        if(m>maxn)
        {
            ans+=n/g*(m-maxn);
        }
        printf("%lld\n",ans);
    }
    return 0;
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值