【zzy】yyy送礼物

题目链接
【分析】

  • 就是求 Σ i = 1 n &lt; n &gt; i \Sigma_{i=1}^n &lt;n&gt;_i Σi=1n<n>i
  • 与除法分块相同,但是数据范围更小,查询次数更多
  • 考虑递推求解
  • f ( n ) = Σ i = 1 n &lt; n &gt; i f(n)=\Sigma_{i=1}^{n}&lt;n&gt;_i f(n)=Σi=1n<n>i
  • f ( n − 1 ) = Σ i − 1 n − 1 &lt; n − 1 &gt; i f(n-1)=\Sigma_{i-1}^{n-1}&lt;n-1&gt;_i f(n1)=Σi1n1<n1>i
  • 不考虑 n ≡ 0 ( m o d n \equiv 0(mod n0(mod i ) i) i)的情况, f ( n ) = f ( n − 1 ) + ( n − 1 ) f(n)=f(n-1)+(n-1) f(n)=f(n1)+(n1)
  • n ≡ 0 ( m o d n \equiv 0(mod n0(mod i ) i) i)时,对 f ( n ) f(n) f(n)的贡献为 − ( σ ( n ) − n ) -(\sigma(n)-n) (σ(n)n)
  • 所以 f ( n ) = f ( n − 1 ) + ( n − 1 ) − ( σ ( n ) − n ) f(n)=f(n-1)+(n-1)-(\sigma(n)-n) f(n)=f(n1)+(n1)(σ(n)n)
  • σ \sigma σ可以用线性筛求出

【代码】

#include <cstdio>
#include <cstring>
#include <algorithm>
#define LL long long
using namespace std;

const int N = 1e7 + 10;

int T, n;
int p[N], pr;
LL sigma[N], f[N], low[N];

void sieve(int n) {
  sigma[1] = 1;
  for (int i = 2; i <= n; ++i) {
    if (low[i] == 0) {
      low[i] = p[++pr] = i;
      sigma[i] = i + 1;
    }
    for (int j = 1, k = i * p[j]; j <= pr && k <= n; ++j, k = i * p[j]) {
      if (i % p[j] == 0) {
        low[k] = low[i] * p[j];
        if (low[k] == k)
          sigma[k] = (low[k] * p[j] - 1) / (p[j] - 1);
        else
          sigma[k] = sigma[i / low[i]] * sigma[low[i] * p[j]];
        break;
      } else {
        low[k] = p[j];
        sigma[k] = sigma[i] * sigma[p[j]];
      }
    }
  }
  for (int i = 1; i <= n; ++i)
    f[i] = f[i - 1] + (i - 1) - (sigma[i] - i);
}

int main() {
  sieve(10000000);
  scanf("%d", &T);
  for (int i = 1; i <= T; ++i) {
    scanf("%d", &n);
    printf("%lld\n", f[n]);
  }
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值