【UOJ188】【UR #13】Sanrd

【题目链接】

【思路要点】

  • f ( x ) 表示 x 次大的质因子,那么答案即为 i = l r f ( i ) ,也就是说我们要求的实际上是 i = 1 N f ( i )

  • 考虑从小到大枚举每一个质因子,最后第二个被枚举到的质因子即为 f ( x )

  • 类似 M i n 25 筛的过程,我们令 s ( N , i ) 表示上次选择的质因子为 p r i m e i 1 ,剩余部分的乘积不超过 N 的数的 f ( x ) 之和。

  • s ( N , i ) = { 0 p r i m e i > N p r i m e i 1 ( j = 1 N [ j   i s   a   p r i m e ] ( j 1 ) ) + j = i p r i m e j 2 N k = 1 p r i m e j k + 1 N ( s ( N p r i m e j k , j + 1 ) + p r i m e j ) p r i m e i N

  • 那么 i = 1 N f ( i ) = s ( N , 1 )

  • 时间复杂度 O ( N 3 4 L o g N )

【代码】


#include<bits/stdc++.h>

using namespace std;
const int MAXN = 700005;
typedef unsigned long long ull;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
  x = 0; int f = 1;
  char c = getchar();
  for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
  for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
  x *= f;
}
template <typename T> void write(T x) {
  if (x < 0) x = -x, putchar('-');
  if (x > 9) write(x / 10);
  putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
  write(x);
  puts("");
}
ull n, limit, val[MAXN], cnt[MAXN];
int m, tot, prime[MAXN], f[MAXN], home1[MAXN], home2[MAXN];
void init(int n) {
  tot = 0;
  for (int i = 2; i <= n; i++)
      f[i] = 0;
  for (int i = 2; i <= n; i++) {
      if (f[i] == 0) prime[++tot] = f[i] = i;
      for (int j = 1; j <= tot && prime[j] <= f[i]; j++) {
          int tmp = prime[j] * i;
          if (tmp > n) break;
          f[tmp] = prime[j];
      }
  }
}
ull s(ull x, int y) {
  if (x <= 1 || prime[y] > x) return 0;
  ull ans = 0;
  if (x <= limit) ans = cnt[home1[x]] - (y - 1);
  else ans = cnt[home2[n / x]] - (y - 1);
  ans *= prime[y - 1];
  for (int i = y; i <= tot && 1ull * prime[i] * prime[i] <= x; i++) {
      ull now = prime[i], nxt = now * now;
      for (int j = 1; nxt <= x; j++, now *= prime[i], nxt *= prime[i])
          ans += s(x / now, i + 1) + prime[i];
  }
  return ans;
}
ull solve(ull x) {
  n = x;
  limit = sqrt(n);
  init(limit);
  m = 0;
  for (ull i = 1, nxt; i <= n; i = nxt) {
      ull tmp = n / i;
      nxt = n / tmp + 1;
      val[++m] = tmp;
      cnt[m] = tmp - 1;
      if (tmp <= limit) home1[tmp] = m;
      else home2[i] = m; 
  }
  for (int i = 1; i <= tot; i++)
  for (int j = 1; 1ull * prime[i] * prime[i] <= val[j]; j++) {
      ull tmp = val[j] / prime[i];
      if (tmp <= limit) cnt[j] -= cnt[home1[tmp]] - (i - 1);
      else cnt[j] -= cnt[home2[n / tmp]] - (i - 1);
  }
  return s(n, 1);
}
int main() {
  ull l, r; read(l), read(r);
  writeln(solve(r) - solve(l - 1));
  return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39972971/article/details/81569229
今日推荐