51nod 1220 约数之和

题意:(sum_{i=1}^n sum_{j=1}^n sigma(i imes j), n leq 1e9)

题解:惭愧。

说到约数和,我们可能能想起约数个数和:(d(i imes j)=sum_{p|i}sum_{q|j}[(x,y)==1])

我们考虑把每个因子一一映射。

如果 (i imes j) 的因子 (k) 中有一个因子 (p^c)(i) 中有因子 (p^a)(j) 中有因子 (p^b) 。我们规定:

  • 如果 (cleq a),那么在 (i) 中选择。
  • 如果 (c>a),那么我们把 (c) 减去 (a),在 (j) 中选择 (p^{c-a})(在 (j) 中选择 (p^e) 表示的是 (p^{a+e})

对于 (i imes j) 的因子 (k) 的其他因子同理。于是对于任何一个 (k) 有一个唯一的映射,且每一个选择对应着唯一的 (k)
通过如上过程,我们发现:对于 (i imes j) 的因子 (k=prod {p_i}^{c_i}) ,我们不可能同时在 (i)(j) 中选择 (p_i) (优先在 (i) 中选择,如果不够就只在 (j) 中选择不够的指数),故 (x)(y) 必须互质。

等式得证。

From Siyuan@luogu

有一个式子: (sigma(i imes j)=sum_{x|i}sum_{y|j} frac{i}{x}y[(x,y)==1])

证明仍然类似上面考虑,如果 (i imes j) 的因子 (k) 中有一个因子 (p^c)(i) 中有因子 (p^a)(j) 中有因子 (p^b) 。我们规定:

  • 如果 (cleq a),那么在 (i) 中选择,这个时候 (x) 中包含 (p^{a-c}) ,所以此时 (frac{i}{x}) 贡献了 (p^c)
  • 如果 (c>a),那么我们把 (c) 减去 (a),在 (j) 中选择 (p^{c-a}) ,即此时 (y) 中包含 (p^{c-a})

此时对于 (i imes j) 的因子 (k=prod {p_i}^{c_i}) 仍然有唯一的映射。

所以可以化式子了:

(=sum_{i=1}^n sum_{j=1}^n sum_{x|i} sum_{y|j} frac{i}{x}y [(x,y)==1])

(=sum_{i=1}^n sum_{j=1}^n sum_{x|i} sum_{y|j} frac{i}{x}y sum_{d|gcd(x,y)} mu(d))

$=sum_{i=1}^n sum_{j=1}^n sum_{d|gcd(i,j)} mu(d) sum_{x|frac{i}{d}} sum_{y|frac{j}{d}} frac{i}{x}y $

$=sum_{d=1}^{n}d mu(d) sum_{i=1}^{frac{n}{d}} sum_{j=1}^{frac{n}{d}} sum_{x|i} sum_{y|j} frac{i}{x}y $

$=sum_{d=1}^{n}d mu(d) (sum_{i=1}^{frac{n}{d}} sum_{x|i} frac{i}{x}) (sum_{j=1}^{frac{n}{d}} sum_{y|j} y) $

$=sum_{d=1}^{n}d mu(d) (sum_{i=1}^{frac{n}{d}} sigma(i))^2 $

然后 (sum_{i=1}^{frac{n}{d}} sigma(i)) 注意到ta的上界显然是可以除法分块的,此时我们再在前头套个杜教筛即可。
最后就是 (sum_{i=1}^n sigma(i) = sum_{i=1}^n ilfloor frac{n}{i} floor) ,表示 (i) 出现了几次。

#pragma GCC optimize(2)
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring> 
#define R register int
#define ll long long
using namespace std;
namespace Luitaryi {
const int N=1000000,M=1000000007;
int n,cnt;
int mu[N+10],p[N>>1];
ll s[N+10],c[N+10];
bool vis[N+10];
inline void pre(int n) {
  mu[1]=1,s[1]=1;
  for(R i=2;i<=n;++i) {
    if(!vis[i]) p[++cnt]=i,mu[i]=-1,s[i]=i+1,c[i]=i+1;
    for(R j=1,k;j<=cnt&&i*p[j]<=n;++j) {
      k=i*p[j]; vis[k]=true;
      if(i%p[j]==0) {
        c[k]=c[i]*p[j]+1;
        s[k]=s[i]/c[i]*c[k];
        break;
      } mu[k]=-mu[i];
      c[k]=p[j]+1;
      s[k]=s[i]*(p[j]+1);
    }
  }
  for(R i=1;i<=n;++i) mu[i]=(mu[i-1]+mu[i]*i+M)%M;
  for(R i=1;i<=n;++i) s[i]=(s[i-1]+s[i])%M;
}
int memmu[64000],SZ;
#define sqr(x) (1ll*(x)*(x+1)/2%M)
inline int calmu(int x) {
  if(x<=N) return mu[x];
  R& ret=x>SZ?memmu[SZ+n/x]:memmu[x];
  if(ret!=memmu[0]) return ret;
  R ans=1,lst=1,now;
  for(R l=2,r;l<=x;l=r+1) {
    r=x/(x/l),now=sqr(r);
    ans=(ans-1ll*(now-lst)*calmu(x/l))%M;
    lst=now;
  } 
  return ret=(ans+M)%M;
}
inline int cals(int x) {
  if(x<=N) return s[x];
  R ret=0,lst=0,now;
  for(R l=1,r;l<=x;l=r+1) {
    r=x/(x/l);
    now=sqr(r);
    ret=(ret+1ll*(now-lst)*(x/l))%M;
    lst=now;
  } return (ret+M)%M;
}
inline void main() {
  pre(N); scanf("%d",&n); SZ=sqrt(n);
  memset(memmu,0xcf,sizeof memmu);
  R ans=0,lst=0,now,tmp;
  for(R l=1,r;l<=n;l=r+1) { 
    r=n/(n/l),now=calmu(r),tmp=cals(n/l);
    tmp=1ll*tmp*tmp%M;
    ans=(ans+1ll*(now-lst)*tmp)%M;
    lst=now;
  } printf("%d
",(ans+M)%M);
}
} signed main() {Luitaryi::main(); return 0;}

2019.12.23

原文地址:https://www.cnblogs.com/Jackpei/p/12087921.html