codeforces 665F. Four Divisors(求n以内因子数是4的数的个数)

time limit per test
10 seconds
memory limit per test
768 megabytes
input
standard input
output
standard output

If an integer a is divisible by another integer b, then b is called the divisor of a.

For example: 12 has positive 6 divisors. They are 12346 and 12.

Let’s define a function D(n) — number of integers between 1 and n (inclusive) which has exactly four positive divisors.

Between 1 and 10 only the integers 68 and 10 has exactly four positive divisors. So, D(10) = 3.

You are given an integer n. You have to calculate D(n).

Input

The only line contains integer n (1 ≤ n ≤ 1011) — the parameter from the problem statement.

Output

Print the only integer c — the number of integers between 1 and n with exactly four divisors.

Examples
input
10
output
3
input
20
output
5

题意:

输入一个数n,求n以内并且只有4个不同因子的数的个数

思路:

每一个数至少存在两个因子,1和本身。

一个数仅存在四个不同的因子,那么这个数必定是某个素数的3次方或者是两个不同素数的乘积

1、n以内且是某个素数的3次方得到个数,很好求,直接将n开三次方得到x,求x以内的素数的个数即可

2、两个不同素数的乘积,枚举较小的素数a,得到b=n/a,对于不同的a,求出b以内的素数的个数,相加去重即可

那么问题就转化成了数m以内的素数个数的问题,恰好可以套用模板:hdu 5901


#include <bits/stdc++.h>
using namespace std;
#define ll __int64

const int N=320005;   
ll phi[10005][105], p2[N], ans[N];  
int len, vis[N];  
  
void init(){  
    len = 0;  
    for(int i=2; i<N; i++){  
        if(!vis[i]){  
            for(int j=i+i; j<N; j+=i) vis[j]=1;  
            p2[len++] = i;  
            ans[i] = ans[i-1]+1;  
            continue;  
        }  
        ans[i] = ans[i-1];  
    }     
    for(int i=0; i<=10000; i++){  
        phi[i][0] = (ll)i;  
        for(int j=1; j<=100; j++){  
            phi[i][j] = phi[i][j-1] - phi[i/p2[j-1]][j-1];  
        }  
    }  
}  
  
ll solve_phi(ll m, ll n){  
    if(!n) return m;  
    if(p2[n - 1] >= m) return 1;  
    if(m<=10000 && n<=100) return phi[m][n];  
    return solve_phi(m, n-1) - solve_phi(m/p2[n-1], n-1);  
}  
  
ll solve_p2(ll m){  
    if(m < (ll)N) return ans[m];  
      
    ll y = (int)cbrt(m*1.0);  
    ll n = ans[y];  
    ll sum = solve_phi(m, n) + n -1;  
      
    for(ll i=n; p2[i]*p2[i]<=m; i++) 
        sum = sum - solve_p2(m/p2[i])+solve_p2(p2[i])-1;  
    return sum;  
}  

int main(){
	init();
	ll n;
	scanf("%I64d", &n);
	ll S = cbrt(n*1.0);
	S = solve_p2(S);
	ll tmp=0;
	for(int i=0; i<len; i++){
		if(p2[i]*p2[i]>=n) break;
		ll x = n/p2[i];
		ll s = solve_p2(x);
		s-=tmp+1;
		tmp = solve_p2(p2[i]);
		S+=s;
	}
	printf("%I64d\n", S);
	return 0;
} 





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值