2019牛客暑期多校D.Big Integer

题面

题意:

定义 A ( n ) A(n) A(n) n n n个1构成的数字,如 A ( 3 ) = 111 A(3)=111 A(3)=111,计算有多少对 ( i , j ) (i,j) (i,j)使得 A ( i j ) % p = 0 A(i^j) \% p = 0 A(ij)%p=0

思路:

通过枚举发现是有上面的等式是有循环节的,而且循环节是 p − 1 p-1 p1的因子,因此暴力枚举计算出循环节 d d d,接下来就是求有多少对 i j % d = 0 i^j \% d=0 ij%d=0
d d d进行质因子分解,得
d = p 1 q 1 ⋅ p 2 q 2 ⋅ p 3 q 3 . . . p k q k d={p_1}^{q_1} \cdot {p_2}^{q_2} \cdot {p_3}^{q_3} ...{p_k}^{q_k} d=p1q1p2q2p3q3...pkqk

那么要使 i j % d = 0 i^j \%d = 0 ij%d=0,则 i i i必须为
g = p 1 ⌈ q 1 j ⌉ ⋅ p 2 ⌈ q 2 j ⌉ ⋅ p 3 ⌈ q 3 j ⌉ . . . p k ⌈ q k j ⌉ g={p_1}^{\lceil {\frac{q_1}{j}} \rceil} \cdot {p_2}^{\lceil {\frac{q_2}{j}} \rceil} \cdot {p_3}^{\lceil {\frac{q_3}{j}} \rceil} ...{p_k}^{\lceil {\frac{q_k}{j}} \rceil} g=p1jq1p2jq2p3jq3...pkjqk
的倍数。因此一共有 n g \frac{n}{g} gn个合法的 i i i
由于 q i ≤ 30 q_i \leq 30 qi30,因此 j j j 30 30 30之后和 30 30 30的答案相同,因此 j j j只需要枚举到 [ 1 , 30 ] [1,30] [1,30],分别计算出 g g g的值。

代码:

#include<bits/stdc++.h>
 
using namespace std;
long long qpow(long long a,long long b,long long mod){
    long long ans=1;
    while(b){
        if(b&1) ans=(ans%mod*a%mod)%mod;
        a=(a%mod*a%mod)%mod;
        b>>=1;
    }
    return ans%mod;
}
long long qp(long long a,long long b){
	long long ans=1;
	while(b){
		if(b&1) ans=(ans*a);
		a=(a*a);
		b>>=1;
	}
	return ans;
}
int main(){
    int T;
    //freopen("1.in","r",stdin);
    scanf("%d",&T);
    while(T--){
        long long ans=0;
        long long p,n,m;
        vector<long long> pr;
        long long re;
        scanf("%lld %lld %lld",&p,&n,&m);
        if(p==2||p==5){
            puts("0");
            continue;
        }
        if(p==3){
        	cout<<n/3*m<<endl;
        	continue;
        }
        vector<long long> all;
        for(int i=2;i*i<=p-1;i++){
            if((p-1)%i==0){
                if(i*i==p-1) all.push_back(i);
                else{
                    all.push_back(i);
                    all.push_back((p-1)/i);
                }
            }
        }
        all.push_back(p-1);
        long long id;//循环节
        sort(all.begin(),all.end());
        for(auto v:all){//找到循环节
            if((qpow(10,v,p))%p==1){
                id=v;break;
            }
        }
        vector<long long> nums;
        for(int i=2;i*i<=id;i++){//质因子分解
            if(id%i==0){
            	 int num=0;
                pr.push_back(i);
                while(id%i==0){
                	 id/=i;
                	 num++;
                }
                nums.push_back(num);
            }  
        }
        if(id!=1){
        	 pr.push_back(id);
        	 nums.push_back(1);
        }
        long long g;
        for(long long j=1;j<=min((long long)m,(long long)30);j++){
        	g=1;
        	for(int i=0;i<(int)nums.size();i++){
        		g*=qp(pr[i],(nums[i]+j-1)/j);
        	}
        	if(j==30) ans+=(n/g)*(m-29);
        	else ans+=n/g;
        }
        printf("%lld\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值