Project Euler 501 Eight Divisors (数论)

题目链接:

https://projecteuler.net/problem=501

题意:

\(f(n)\) be the count of numbers not exceeding \(n\) with exactly eight divisors.

就是找少于等于 \(n\)中只有8个因子的个数。

You are given \(f(100) = 10, f(1000) = 180\) and \(f(10^6) = 224427\).

Find \(f(10^{12})\)

题解:

我们知道,对于 \(n=\prod p_i^{a_i}\) ,那么,\(n\)的因子的个数有 \(\prod (a_i+1)\)个。

那么,符合题目条件的只有三种情况。

\(1.p^{7} <= n\)

\(2.p^{3} * q <= n\)

\(3.p * q * r <= n\)'

其中,\(p,q,r\)是各自不相等的质数,并且 \(p < q < r\)

和这题套路一样。

http://codeforces.com/problemset/problem/665/F

Codefores这题代码:

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

const int MAX = 2e6+5;   
const int M = 7;         
typedef long long ll;
vector<int> lp, primes, pi;
int phi[MAX+1][M+1], sz[M+1];

void factor_sieve()
{
	lp.resize(MAX);
	pi.resize(MAX);
	lp[1] = 1;
	pi[0] = pi[1] = 0;
	for (int i = 2; i < MAX; i++) {
		if (lp[i] == 0) {
			lp[i] = i;
			primes.emplace_back(i);
		}
		for (int j = 0; j < primes.size() && primes[j] <= lp[i]; j++) {
			int x = i * primes[j];
			if (x >= MAX) break;
			lp[x] = primes[j];
		}
		pi[i] = primes.size();
	}
}

void init()
{
	factor_sieve();
	for(int i = 0; i <= MAX; i++) {
		phi[i][0] = i;
	}
	sz[0] = 1;
	for(int i = 1; i <= M; i++) {
		sz[i] = primes[i-1]*sz[i-1];
		for(int j = 1; j <= MAX; j++) {
			phi[j][i] = phi[j][i-1] - phi[j/primes[i-1]][i-1];
		}
	}
}

int sqrt2(long long x)
{
	long long r = sqrt(x - 0.1);
	while (r*r <= x) ++r;
	return r - 1;
}

int cbrt3(long long x)
{

	long long r = cbrt(x - 0.1);
	while(r*r*r <= x) ++r;
	return r - 1;
}

long long getphi(long long x, int s)
{
	if(s == 0)  return x;
	if(s <= M)
        {
		return phi[x%sz[s]][s] + (x/sz[s])*phi[sz[s]][s];
	}
	if(x <= primes[s-1]*primes[s-1])
       {
		return pi[x] - s + 1;
	}
	if(x <= primes[s-1]*primes[s-1]*primes[s-1] && x < MAX)
        {
		int sx = pi[sqrt2(x)];
		long long ans = pi[x] - (sx+s-2)*(sx-s+1)/2;
		for(int i = s+1; i <= sx; ++i) {
			ans += pi[x/primes[i-1]];
		}
		return ans;
	}
	return getphi(x, s-1) - getphi(x/primes[s-1], s-1);
}

long long getpi(long long x)
{
	if(x < MAX)   return pi[x];
	int cx = cbrt3(x), sx = sqrt2(x);
	long long ans = getphi(x, pi[cx]) + pi[cx] - 1;
	for(int i = pi[cx]+1, ed = pi[sx]; i <= ed; i++)
       {
		ans -= getpi(x/primes[i-1-1]) - i + 1;
	}
	return ans;
}

long long lehmer_pi(long long x)
{
	if(x < MAX)   return pi[x];
	int a = (int)lehmer_pi(sqrt2(sqrt2(x)));
	int b = (int)lehmer_pi(sqrt2(x));
	int c = (int)lehmer_pi(cbrt3(x));
	long long sum = getphi(x, a) + (long long)(b + a - 2) * (b - a + 1) / 2;
	for (int i = a + 1; i <= b; i++)
       {
		long long w = x / primes[i-1];
		sum -= lehmer_pi(w);
		if (i > c) continue;
		long long lim = lehmer_pi(sqrt2(w));
		for (int j = i; j <= lim; j++)
               {
			sum -= lehmer_pi(w / primes[j-1]) - (j - 1);
		}
	}
	return sum;
}

long long power(long long a, long long b)
{
	long long x = 1, y = a;
	while(b)
      {
		if (b&1)  x = x * y;
		y = y * y;
		b >>= 1;
	}
	return x;
}
void solve(long long n)
{
  ll ans = 0;
  // case 1: p^3 <= n ,p is a prime
  for(int i = 0; i < (int)primes.size(); i++) {
    if (power(primes[i], 3) <= n) {
      //std::cout << primes[i] << '\n';
      ans += 1;
    }
    else {
      break;
    }
  }
  //  std::cout << "ans=" <<ans << '\n'<<'\n';
  // case 2: p*q <= n (p < q)
  // p, q is distinct primes
  ll cnt = 0;
  ll q = 0;
  for(int i = 0; i < (int)primes.size(); i++) //p
  {
    ll x = (ll)primes[i]; // p
    q = n / x; //q
    if(q <= x)continue;
    if(q == 0)continue;
    //std::cout << "p=" << x << '\n';
    //std::cout << "q=" << q << '\n';
    cnt = lehmer_pi(q);
    if (q >= primes[i]) {
      cnt -= lehmer_pi(x);
    }
    if (cnt <= 0) break;
    //std::cout << "cnt=" <<cnt << '\n';
    ans += cnt;
  }
  //  std::cout << "p*q finish!" << '\n';

  std::cout << ans << '\n';
}
int main(int argc, char const *argv[])
{
  ll n;
  init();
  scanf("%lld", &n);
  solve(n);
  return 0;
}

PE501代码:

利用 Lucy_Hedgehog's method. \(O(n^{3/4})\)。跑10min左右...太慢了..

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2000010;
vector<int> mark,prime;
void init()
{
    mark.resize(maxn);
    mark[1] = 1;
    for (int i = 2; i < maxn; i++)
    {
	if (mark[i] == 0)
	{
	    mark[i] = i;
	    prime.emplace_back(i);
	}
	for (int j = 0; j < (int)prime.size() && prime[j] <= mark[i]; j++)
	{
	   int x = i * prime[j];
	   if (x >= maxn) break;
	   mark[x] = prime[j];
	}
    }
}
ll check(ll v, ll n, ll ndr, ll nv) {
    return v >= ndr ? (n / v - 1) : (nv - v);
}
ll primenum(ll n) // O(n^(3/4))
{
  assert(n>=1);
  ll r = (ll)sqrt(n);
  ll ndr = n / r;
  assert(r*r <= n && (r+1)*(r+1) > n);
  ll nv = r + ndr - 1;
  std::vector<ll> S(nv+1);
  std::vector<ll> V(nv+1);
  for(ll i=0;i<r;i++) {
    V[i] = n / (i+1);
  }
  for(ll i=r;i<nv;i++) {
    V[i] = V[i-1] - 1;
  }
  for(ll i = 0;i<nv;i++) {
    S[i] = V[i] - 1; //primes number
  }
  for(ll p=2;p<=r;p++) {
    if(S[nv-p] > S[nv-p+1]) {
      ll sp = S[nv-p+1]; // sum of primes smaller than p
      ll p2 = p*p;
  //    std::cout << "p=" << p << '\n'; // p is prime
      for(ll i=0;i<nv;i++) {
        if(V[i] >= p2) {
          S[i] -= 1LL  * (S[check(V[i] / p, n, ndr, nv)] - sp);
        }
        else break;
      }
    }
  }
  ll ans = S[0];
  return ans;
}

ll qpower(ll a, ll b)
{
   ll res = 1;
   while(b)
   {
	if (b&1)  res = res * a;
	a = a * a;
	b >>= 1;
   }
   return res;
}

void solve(ll n)
{

  ll ans = 0;
  // case 1: p^7 <= n ,p is a prime
  for(int i = 0; i < (int)prime.size(); i++) {
    // for example 2^7 = 128 <=n
    if (qpower(prime[i], 7) <= n) {
      //std::cout << primes[i] << '\n';
      ans += 1;
    }
    else {
      break;
    }
  }
  std::cout << "p^7 finish!" << '\n';

  // case 2: p^3*q <= n (p < q)
  // p, q is distinct primes
  ll cnt = 0;
  for(int i = 0; i < (int)prime.size(); i++) //p
  {
    ll x = (ll)prime[i]*prime[i]*prime[i]; // p^3
    x = n / x; //q
    if(x == 0)continue;
    cnt = primenum(x);
    if (x >= prime[i]) {
      cnt -= 1;
    }
    if (cnt <= 0) break;
    ans += cnt;
  }
  std::cout << "p^3*q finish!" << '\n';

  //case 3: p*q*r <= n (p < q < r)
  // p,q,r is distinct primes
  for(int i = 0; i < (int)prime.size(); i++) // p
  {
    if (qpower(prime[i], 3) > n) {
      break;
    }
    for(int j = i+1; j < (int)prime.size(); j++) // q
    {
      ll x = n / ((ll)prime[i]*prime[j]);
      if(x <= j)continue;
      if(x == 0)continue;
      cnt = primenum(x); // r
      cnt -= j+1;
      if (cnt <= 0) break;
      ans += cnt;
    }
  }
  std::cout << "p*q*r finish!" << '\n';
  std::cout << ans << '\n';
  cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
}
int main(int argc, char const *argv[])
{
  /* code */
  init();
  solve(100);
  solve(1000);
  solve(1000000);
  solve(1e12);
  return 0;
}

利用Meisell-Lehmer's method。\(O(n^{2/3})\)。跑10s..

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

const int MAX = 2e6+5;  
const int M = 7;      

vector<int> lp, primes, pi;
int phi[MAX+1][M+1], sz[M+1];

void factor_sieve()
{
	lp.resize(MAX);
	pi.resize(MAX);
	lp[1] = 1;
	pi[0] = pi[1] = 0;
	for (int i = 2; i < MAX; i++) {
		if (lp[i] == 0) {
			lp[i] = i;
			primes.emplace_back(i);
		}
		for (int j = 0; j < primes.size() && primes[j] <= lp[i]; j++) {
			int x = i * primes[j];
			if (x >= MAX) break;
			lp[x] = primes[j];
		}
		pi[i] = primes.size();
	}
}

void init()
{
	factor_sieve();
	for(int i = 0; i <= MAX; i++) {
		phi[i][0] = i;
	}
	sz[0] = 1;
	for(int i = 1; i <= M; i++) {
		sz[i] = primes[i-1]*sz[i-1];
		for(int j = 1; j <= MAX; j++) {
			phi[j][i] = phi[j][i-1] - phi[j/primes[i-1]][i-1];
		}
	}
}

int sqrt2(long long x)
{
	long long r = sqrt(x - 0.1);
	while (r*r <= x) ++r;
	return r - 1;
}

int cbrt3(long long x)
{

	long long r = cbrt(x - 0.1);
	while(r*r*r <= x) ++r;
	return r - 1;
}

long long getphi(long long x, int s)
{
	if(s == 0)  return x;
	if(s <= M)
  {
		return phi[x%sz[s]][s] + (x/sz[s])*phi[sz[s]][s];
	}
	if(x <= primes[s-1]*primes[s-1])
  {
		return pi[x] - s + 1;
	}
	if(x <= primes[s-1]*primes[s-1]*primes[s-1] && x < MAX)
  {
		int sx = pi[sqrt2(x)];
		long long ans = pi[x] - (sx+s-2)*(sx-s+1)/2;
		for(int i = s+1; i <= sx; ++i) {
			ans += pi[x/primes[i-1]];
		}
		return ans;
	}
	return getphi(x, s-1) - getphi(x/primes[s-1], s-1);
}

long long getpi(long long x)
{
	if(x < MAX)   return pi[x];
	int cx = cbrt3(x), sx = sqrt2(x);
	long long ans = getphi(x, pi[cx]) + pi[cx] - 1;
	for(int i = pi[cx]+1, ed = pi[sx]; i <= ed; i++)
  {
		ans -= getpi(x/primes[i-1-1]) - i + 1;
	}
	return ans;
}

long long lehmer_pi(long long x)
{
	if(x < MAX)   return pi[x];
	int a = (int)lehmer_pi(sqrt2(sqrt2(x)));
	int b = (int)lehmer_pi(sqrt2(x));
	int c = (int)lehmer_pi(cbrt3(x));
	long long sum = getphi(x, a) + (long long)(b + a - 2) * (b - a + 1) / 2;
	for (int i = a + 1; i <= b; i++)
  	{
		long long w = x / primes[i-1];
		sum -= lehmer_pi(w);
		if (i > c) continue;
		long long lim = lehmer_pi(sqrt2(w));
		for (int j = i; j <= lim; j++)
    	{
			sum -= lehmer_pi(w / primes[j-1]) - (j - 1);
		}
	}
	return sum;
}

long long power(long long a, long long b)
{
	long long x = 1, y = a;
	while(b)
  {
		if (b&1)  x = x * y;
		y = y * y;
		b >>= 1;
	}
	return x;
}
void solve(long long n)
{
  	init();
  	long long ans = 0, val = 0;

	// case : p^7 <= n ,p is a prime
	for(int i = 0; i < primes.size(); i++) {
        // for example 2^7 = 128 <=n
		if (power(primes[i], 7) <= n) {
          //std::cout << primes[i] << '\n';
			ans += 1;
		}
		else {
			break;
		}
	}
    //  std::cout << "ans = " << ans << '\n';

	// case : p^3*q <= n (assume q > p for finding unique pairs)
       // p, q is distinct primes
	for(int i = 0; i < primes.size(); i++) //p
  	{
		long long x = (long long)primes[i]*primes[i]*primes[i]; // p^3
		x = n / x; //q
		val = lehmer_pi(x);
		if (x >= primes[i]) {
			val -= 1;
		}
		if (val <= 0) break;
		ans += val;
	}
	//case : p*q*r <= n (assume r > q > p for finding unique pairs)
        // p,q,r is distinct primes
	for(int i = 0; i < primes.size(); i++) // p
  	{
		if (power(primes[i], 3) > n) {
			break;
		}
		for(int j = i+1; j < primes.size(); j++) // q
    	       {
			long long x = n / ((long long)primes[i]*primes[j]);
      		        if(x < j)continue;
			val = lehmer_pi(x); // r
			val -= j+1; // 减去 计算 <=x 的素数个数中多余的
			if (val <= 0) break;
			ans += val;
		}
	}
	std::cout << ans << '\n';
  	cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
}
int main(int argc, char const *argv[])
{
  /* code */
  solve(1e12);
  return 0;
}

posted @ 2018-02-18 20:54  LzyRapx  阅读(386)  评论(1编辑  收藏  举报