1. 程式人生 > >【zzy】yyy送禮物

【zzy】yyy送禮物

題目連結
【分析】

  • 就是求Σi=1n<n>i\Sigma_{i=1}^n <n>_i
  • 與除法分塊相同,但是資料範圍更小,查詢次數更多
  • 考慮遞推求解
  • f(n)=Σi=1n<n>if(n)=\Sigma_{i=1}^{n}<n>_i
  • f(n1)=Σi1n1<n1>if(n-1)=\Sigma_{i-1}^{n-1}<n-1>_i
  • 不考慮n0(modn \equiv 0(mod i)i)的情況,f(n)=f(n1)+(n1)f(n)=f(n-1)+(n-1)
  • n0(modn \equiv 0(mod i)i)時,對f(n)f(n)的貢獻為(σ(n)n)-(\sigma(n)-n)
  • 所以f(n)=f(n1)+(n1)(σ(n)n)f(n)=f(n-1)+(n-1)-(\sigma(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; }