牛牛的k合因子数(约数个数定理求约数个数)

题目描述

链接:https://ac.nowcoder.com/acm/contest/3004/H
来源:牛客网

约数个数定理

百度百科链接:
https://baike.baidu.com/item/约数个数定理/4926961?fr=aladdin
对于一个大于1正整数n可以分解质因数:
n = p1a1 · p2a2· p3a3· p4a4······pnan

则n的正约数的个数就是:
f(n) = (a1+1)(a2+1)(a3+1)(a4+1)······(an+1)

其中a1、a2、a3、a4、…an是p1、p2、p3、p4、…pn的指数

f(n) = (a1+1)(a2+1)(a3+1)(a4+1)······(an+1)的证明就是乘法原理

例如:

36的因数有9个为:

1 2 3 4 6 9 13 18 36

36=4·9=(22)(32)

f(36)=(2+1)(2+1)=9

个人理解:

分解质因数后可得:

n = p1a1 · p2a2· p3a3· p4a4······pnan(式一)

若p1是n的一个因数
则有:

p10 是n的一个因数 n%p10 ==0
p11 是n的一个因数 n%p11==0

·
·
·
p1a1是n的一个因数 n%p1a1==0

对于p2、p3……pn都满足上述
因此:
任意a1’(0到a1)个p1
任意a2’(0到a2)个p2
任意a3’(0到a3)个p3
·
·
·
任意an’(0到an)个pn
(包括0个)
相乘得:
p1a1’×p2a2’×p3a3’×……×pnan’(式二)
都是n的因数

即(式一)%(式二)==0 (可以化简得出)

代码实现
1.素数打表

运算过程中需要用到素数表
prime[n]
可以用素数打表实现
链接:
https://blog.csdn.net/harington/article/details/86571150

2.枚举得到an

通过枚举得an,枚举过程类似于素数打表。
代码:

#include<bits/stdc++.h>
using namespace std;
#define LL long long
LL const mod = 1e9+5;
#define N 1000005
bool isPrime[N];
int prime[N];
int tot;
void get_prime()
{
  for(int i=2;i<N;i++){
   if(!isPrime[i]){      
prime[tot++] = i;
    }   
for(int j=0;j<tot;j++){       
if(prime[j] * i >= N) break;      
isPrime[prime[j] * i] = 1;      
if(i%prime[j] == 0) break;
    }
   }
}//素数打表
LL num[N];
LL ans[N][2];    //一维是所有因数,二维是质因数个数
int main()
{
get_prime();
 LL n,m;
       
scanf("%lld%lld",&n,&m);
       
LL  k[m];
    
for(int i=0;i<m;i++) scanf("%lld",&k[i]);
     
LL K[n+1];
    
memset(K,0,sizeof(K));
       
for(LL i=2;i<=n;i++) ans[i][0] = 1,num[i] = i,ans[i][1]=1;

for(int i=0;i<tot;i++){
        
if(prime[i] > n) break;          
for(LL j=prime[i];j<=n;j+=prime[i]){            
LL cot = 0;
   while(num[j]%prime[i]==0){   
                cot++;         
   num[j] /= prime[i];           
}         
if(cot) ans[j][0] *= (cot  + 1) %mod ; 
ans[j] [0]%= mod;           
ans[j][1]++;          
}       
}   
for(int i=2;i<=n;i++)
    {
           ans[i][0]-=ans[i][1];   
K[ans[i][0]]++;
}
for(int i=0;i<m;i++)
    {
           printf("%lld\n",K[k[i]]);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值