【LOJ6053】简单的函数

本文介绍了一种高效的算法——Min25筛算法,并通过一个模板题进行了详细讲解。该算法的时间复杂度为O(N^(3/4)/logN),适用于解决特定类型的数学问题。文章提供了完整的代码实现,并解释了关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【题目链接】

【思路要点】

【代码】


#include<bits/stdc++.h>

using namespace std;
const int MAXN = 2e5 + 5;
const int P = 1e9 + 7;
const int inv2 = 5e8 + 4;
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("");
}
long long n, limit, m, val[MAXN];
int tot, prime[MAXN], Min[MAXN], pre[MAXN];
int cnt[MAXN], sum[MAXN], home1[MAXN], home2[MAXN];
int s(long long x, int y) {
  if (x <= 1 || prime[y] > x) return 0;
  int pos = (x <= limit) ? home1[x] : home2[n / x];
  int ans = (sum[pos] - cnt[pos] + P) % P;
  ans = (ans - (pre[y - 1] - y + 1 + P) % P + P) % P;
  if (y == 1) ans = (ans + 2) % P;
  for (int i = y; i <= tot && 1ll * prime[i] * prime[i] <= x; i++) {
      long long now = prime[i], nxt = 1ll * prime[i] * prime[i];
      for (int j = 1; nxt <= x; j++, now *= prime[i], nxt *= prime[i])
          ans = (ans + 1ll * s(x / now, i + 1) * (prime[i] ^ j) + (prime[i] ^ (j + 1))) % P;
  }
  return ans;
}
void init(int n) {
  for (int i = 2; i <= n; i++) {
      if (Min[i] == 0) {
          Min[i] = i;
          prime[++tot] = i;
          pre[tot] = (pre[tot - 1] + i) % P;
      }
      for (int j = 1; j <= tot && prime[j] <= Min[i]; j++) {
          int tmp = prime[j] * i;
          if (tmp > n) break;
          Min[tmp] = prime[j];
      }
  }
}
int main() {
  read(n), limit = sqrt(n);
  init(limit);
  for (long long i = 1, nxt; i <= n; i = nxt) {
      long long tmp = n / i;
      nxt = n / tmp + 1;
      val[++m] = tmp;
      cnt[m] = (val[m] - 1) % P;
      sum[m] = (val[m] + 2) % P * ((val[m] - 1) % P) % P * inv2 % P;
      if (sum[m] < 0) sum[m] += P;
      if (tmp <= limit) home1[tmp] = m;
      else home2[i] = m;
  }
  for (int j = 1; j <= tot; j++)
  for (int i = 1; 1ll * prime[j] * prime[j] <= val[i]; i++) {
      long long tmp = val[i] / prime[j];
      if (tmp <= limit) cnt[i] -= cnt[home1[tmp]] - (j - 1);
      else cnt[i] -= cnt[home2[n / tmp]] - (j - 1);
      cnt[i] = (cnt[i] % P + P) % P;
      if (tmp <= limit) sum[i] -= 1ll * prime[j] * (sum[home1[tmp]] - pre[j - 1]) % P;
      else sum[i] -= 1ll * prime[j] * (sum[home2[n / tmp]] - pre[j - 1]) % P;
      sum[i] = (sum[i] % P + P) % P;
  }
  writeln((1 + s(n, 1)) % P);
  return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值