BZOJ2154 Crash的数字表格及其拓展BZOJ2693 jzptab(Mobius反演)

题目:BZOJ2154.
题目大意:给定 n n n m m m,求:
∑ i = 1 n ∑ j = 1 m l c m ( i , j ) \sum_{i=1}^{n}\sum_{j=1}^{m}lcm(i,j) i=1nj=1mlcm(i,j)

n , m ≤ 1 0 7 n,m\leq 10^7 n,m107.

很容易发现:
∑ i = 1 n ∑ j = 1 m l c m ( i , j ) = ∑ i = 1 n ∑ j = 1 m i j g c d ( i , j ) \sum_{i=1}^{n}\sum_{j=1}^{m}lcm(i,j) =\sum_{i=1}^{n}\sum_{j=1}^{m}\frac{ij}{gcd(i,j)} i=1nj=1mlcm(i,j)=i=1nj=1mgcd(i,j)ij

我们钦定 n ≤ m n\leq m nm,那么:
∑ i = 1 n ∑ j = 1 m l c m ( i , j ) = ∑ k = 1 n 1 k ∑ i = 1 n ∑ j = 1 m i j [ g c d ( i , j ) = k ] \sum_{i=1}^{n}\sum_{j=1}^{m}lcm(i,j)\\ =\sum_{k=1}^{n}\frac{1}{k}\sum_{i=1}^{n}\sum_{j=1}^{m}ij[gcd(i,j)=k] i=1nj=1mlcm(i,j)=k=1nk1i=1nj=1mij[gcd(i,j)=k]

a = ⌊ n k ⌋ , b = ⌊ m k ⌋ a=\left \lfloor \frac{n}{k} \right \rfloor,b=\left \lfloor \frac{m}{k} \right \rfloor a=kn,b=km,那么:
∑ i = 1 n ∑ j = 1 m l c m ( i , j ) = ∑ k = 1 n 1 k ∑ i = 1 a ∑ j = 1 b i j k 2 ∗ [ g c d ( i , j ) = 1 ] = ∑ k = 1 n k ∑ i = 1 a ∑ j = 1 b i j ∑ d ∣ g c d ( i , j ) μ ( d ) = ∑ k = 1 n k ∑ d = 1 a μ ( d ) ∑ i = 1 a ∑ j = 1 b i j [ d ∣ i ] [ d ∣ j ] \sum_{i=1}^{n}\sum_{j=1}^{m}lcm(i,j)\\ =\sum_{k=1}^{n}\frac{1}{k}\sum_{i=1}^{a}\sum_{j=1}^{b}ijk^2*[gcd(i,j)=1]\\ =\sum_{k=1}^{n}k\sum_{i=1}^{a}\sum_{j=1}^{b}ij\sum_{d|gcd(i,j)}\mu(d)\\ =\sum_{k=1}^{n}k\sum_{d=1}^{a}\mu(d)\sum_{i=1}^{a}\sum_{j=1}^{b}ij[d|i][d|j] i=1nj=1mlcm(i,j)=k=1nk1i=1aj=1bijk2[gcd(i,j)=1]=k=1nki=1aj=1bijdgcd(i,j)μ(d)=k=1nkd=1aμ(d)i=1aj=1bij[di][dj]

x = ⌊ a d ⌋ , y = ⌊ b d ⌋ x=\left \lfloor \frac{a}{d} \right \rfloor,y=\left \lfloor \frac{b}{d} \right \rfloor x=da,y=db,那么:
∑ i = 1 n ∑ j = 1 m l c m ( i , j ) = ∑ k = 1 n k ∑ d = 1 a d 2 μ ( d ) ∑ i = 1 x ∑ j = 1 y i j = ∑ k = 1 n k ∑ d = 1 a d 2 μ ( d ) ∗ x ( x + 1 ) 2 ∗ y ( y + 1 ) 2 \sum_{i=1}^{n}\sum_{j=1}^{m}lcm(i,j)\\ =\sum_{k=1}^{n}k\sum_{d=1}^{a}d^2\mu(d)\sum_{i=1}^{x}\sum_{j=1}^{y}ij\\ =\sum_{k=1}^{n}k\sum_{d=1}^{a}d^2\mu(d)*\frac{x(x+1)}{2}*\frac{y(y+1)}{2} i=1nj=1mlcm(i,j)=k=1nkd=1ad2μ(d)i=1xj=1yij=k=1nkd=1ad2μ(d)2x(x+1)2y(y+1)

设函数 f ( x , y ) = x ( x + 1 ) 2 ∗ y ( y + 1 ) 2 f(x,y)=\frac{x(x+1)}{2}*\frac{y(y+1)}{2} f(x,y)=2x(x+1)2y(y+1),那么原式就变为:
∑ i = 1 n ∑ j = 1 m l c m ( i , j ) = ∑ k = 1 n k ∑ d = 1 a d 2 μ ( d ) f ( ⌊ a d ⌋ , ⌊ b d ⌋ ) \sum_{i=1}^{n}\sum_{j=1}^{m}lcm(i,j)\\ =\sum_{k=1}^{n}k\sum_{d=1}^{a}d^2\mu(d)f(\left \lfloor \frac{a}{d} \right \rfloor,\left\lfloor \frac{b}{d} \right\rfloor) i=1nj=1mlcm(i,j)=k=1nkd=1ad2μ(d)f(da,db)

设函数(钦定 x ≤ y x\leq y xy g ( x , y ) = ∑ d = 1 x d 2 μ ( d ) f ( ⌊ x d ⌋ , ⌊ y d ⌋ ) g(x,y)=\sum_{d=1}^{x}d^2\mu(d)f(\left \lfloor \frac{x}{d} \right \rfloor,\left \lfloor \frac{y}{d} \right \rfloor) g(x,y)=d=1xd2μ(d)f(dx,dy),那么原式变为:
∑ i = 1 n ∑ j = 1 m l c m ( i , j ) = ∑ k = 1 n k g ( ⌊ n k ⌋ , ⌊ m k ⌋ ) \sum_{i=1}^{n}\sum_{j=1}^{m}lcm(i,j)= \sum_{k=1}^{n}kg(\left\lfloor \frac{n}{k}\right\rfloor,\left\lfloor\frac{m}{k}\right\rfloor) i=1nj=1mlcm(i,j)=k=1nkg(kn,km)

发现这个式子 g g g函数的计算可以用除法分块优化,而外面式子也可以用除法分块优化,计算这个式子的时间复杂度即为 O ( ( n + m ) 2 ) = O ( n + m ) O((\sqrt{n}+\sqrt{m})^2)=O(n+m) O((n +m )2)=O(n+m).

代码如下:

#include<bits/stdc++.h>
  using namespace std;
 
#define Abigail inline void
typedef long long LL;
 
const int N=10000000;
const LL mod=20101009;
 
int pr[N+9],tp,b[N+9];
LL mu[N+9],div2;
 
LL M(LL x){
  x=x%mod+mod;
  return (x>=mod)?x-=mod:x; 
}
 
void sieve(int n){
  for (int i=2;i<=n;++i) b[i]=1;
  mu[1]=1;
  for (int i=2;i<=n;++i){
    if (b[i]) pr[++tp]=i,mu[i]=-1;
    for (int j=1;j<=tp&&pr[j]*i<=n;++j){
      b[i*pr[j]]=0;
      if (i%pr[j]) mu[i*pr[j]]=-mu[i];
      else {mu[i*pr[j]]=0;break;}
    }
  }
  for (int i=1;i<=n;++i)
    mu[i]=M(mu[i]*i*i+mu[i-1]);
}
 
LL sum(int l,int r){return M(LL(l+r)*LL(r-l+1)>>1);}
LL f(int x,int y){return M(sum(1,x)*sum(1,y));}
 
LL g(int n,int m){
  LL ans=0;
  if (n>m) swap(n,m);
  for (int l=1,r;l<=n;l=r+1){
    r=min(n/(n/l),m/(m/l));
    ans=M(ans+(mu[r]-mu[l-1])*f(n/l,m/l));
  }
  return ans;
}
 
LL Query(int n,int m){
  LL ans=0;
  if (n>m) swap(n,m);
  for (int l=1,r;l<=n;l=r+1){
    r=min(n/(n/l),m/(m/l));
    ans=M(ans+sum(l,r)*g(n/l,m/l));
  }
  return ans;
}
 
Abigail work(){
  sieve(N);
}
 
Abigail getans(){
  int n,m;
  scanf("%d%d",&n,&m);
  printf("%lld\n",Query(n,m));
}
 
int main(){
  work();
  getans();
  return 0;
}

我们再来看一道题,是上面这道题多组询问的形式.

题目:BZOJ2693.
题目大意:多组询问,给定 n n n m m m,求:
∑ i = 1 n ∑ j = 1 m l c m ( i , j ) \sum_{i=1}^{n}\sum_{j=1}^{m}lcm(i,j) i=1nj=1mlcm(i,j)

多组询问了,可是 n n n m m m的数据范围还没变,怎么办呢?

我们考虑这样的问题应该是要预处理然后在低于 O ( n ) O(n) O(n)的时间复杂度内回答询问.

观察下式:
∑ k = 1 n k ∑ d = 1 a μ ( d ) d 2 ∗ x ( x + 1 ) 2 ∗ y ( y + 1 ) x = ∑ k = 1 n k ∑ d = 1 a μ ( d ) d 2 ∗ ⌊ n d k ⌋ ( ⌊ n d k ⌋ + 1 ) 2 ∗ ⌊ m d k ⌋ ( ⌊ m d k ⌋ + 1 ) 2 \sum_{k=1}^{n}k\sum_{d=1}^{a}\mu(d)d^2*\frac{x(x+1)}{2}*\frac{y(y+1)}{x} \\=\sum_{k=1}^{n}k\sum_{d=1}^{a}\mu(d)d^2*\frac{\left \lfloor \frac{n}{dk} \right \rfloor(\left \lfloor \frac{n}{dk} \right \rfloor+1)}{2} *\frac{\left \lfloor \frac{m}{dk} \right \rfloor(\left \lfloor \frac{m}{dk} \right \rfloor+1)}{2} k=1nkd=1aμ(d)d22x(x+1)xy(y+1)=k=1nkd=1aμ(d)d22dkn(dkn+1)2dkm(dkm+1)

我们让 t = d k t=dk t=dk,那么:
∑ k = 1 n k ∑ d = 1 a μ ( d ) d 2 ∗ x ( x + 1 ) 2 ∗ y ( y + 1 ) x = ∑ t = 1 n ∑ d ∣ t μ ( d ) d 2 ∗ t d ∗ ⌊ n t ⌋ ( ⌊ n t ⌋ + 1 ) 2 ∗ ⌊ m t ⌋ ( ⌊ m t ⌋ + 1 ) 2 = ∑ t = 1 n f ( ⌊ n t ⌋ , ⌊ m t ⌋ ) ∗ t ∑ d ∣ t μ ( d ) ∗ d \sum_{k=1}^{n}k\sum_{d=1}^{a}\mu(d)d^2*\frac{x(x+1)}{2}*\frac{y(y+1)}{x}\\ =\sum_{t=1}^{n}\sum_{d|t}\mu(d)d^2*\frac{t}{d}*\frac{\left \lfloor \frac{n}{t} \right \rfloor(\left \lfloor \frac{n}{t} \right \rfloor+1)}{2} *\frac{\left \lfloor \frac{m}{t} \right \rfloor(\left \lfloor \frac{m}{t} \right \rfloor+1)}{2}\\ =\sum_{t=1}^{n}f(\left \lfloor \frac{n}{t} \right \rfloor,\left \lfloor \frac{m}{t} \right \rfloor)*t\sum_{d|t}\mu(d)*d k=1nkd=1aμ(d)d22x(x+1)xy(y+1)=t=1ndtμ(d)d2dt2tn(tn+1)2tm(tm+1)=t=1nf(tn,tm)tdtμ(d)d

我们设一个函数 G ( t ) = t ∑ d ∣ t μ ( d ) d G(t)=t\sum_{d|t}\mu(d)d G(t)=tdtμ(d)d,可以证明这个函数是积性的:
g c d ( a , b ) = 1 gcd(a,b)=1 gcd(a,b)=1时:
G ( a ) G ( b ) = a ∑ d 1 ∣ a μ ( d 1 ) d 1 ∗ b ∑ d 2 ∣ b μ ( d 2 ) d 2 = a b ∑ d 1 ∣ a ∑ d 2 ∣ b μ ( d 1 ) μ ( d 2 ) d 1 d 2 = a b ∑ d 1 ∣ a ∑ d 2 ∣ b μ ( d 1 d 2 ) d 1 d 2 = a b ∑ d ∣ a b μ ( d ) d = G ( a b ) G(a)G(b)\\ =a\sum_{d_1|a}\mu(d_1)d_1*b\sum_{d_2|b}\mu(d_2)d_2\\ =ab\sum_{d_1|a}\sum_{d_2|b}\mu(d_1)\mu(d_2)d_1d_2\\ =ab\sum_{d_1|a}\sum_{d_2|b}\mu(d_1d_2)d_1d_2\\ =ab\sum_{d|ab}\mu(d)d\\ =G(ab) G(a)G(b)=ad1aμ(d1)d1bd2bμ(d2)d2=abd1ad2bμ(d1)μ(d2)d1d2=abd1ad2bμ(d1d2)d1d2=abdabμ(d)d=G(ab)

证毕.

然后我们就可以用线性筛筛这个函数:
1.当 i i i为素数时, G ( i ) = i ( μ ( 1 ) + μ ( i ) i ) = i + i 2 μ ( i ) = i − i 2 G(i)=i(\mu(1)+\mu(i)i)=i+i^2\mu(i)=i-i^2 G(i)=i(μ(1)+μ(i)i)=i+i2μ(i)=ii2.
2.当 g c d ( i , p r [ j ] ) = 1 gcd(i,pr[j])=1 gcd(i,pr[j])=1时,根据积性函数的定义, G ( i ∗ p r [ j ] ) = G ( i ) G ( p r [ j ] ) G(i*pr[j])=G(i)G(pr[j]) G(ipr[j])=G(i)G(pr[j]).
3.当 p r [ j ] ∣ i pr[j]|i pr[j]i时,可以推导出:
G ( i ∗ p r [ j ] ) = i ∗ p r [ j ] ∑ d ∣ i ∗ p r [ j ] μ ( d ) d G(i*pr[j])=i*pr[j]\sum_{d|i*pr[j]}\mu(d)d G(ipr[j])=ipr[j]dipr[j]μ(d)d

考虑将式子拆成两部分,一部分为 d ∣ i d|i di的情况,另一部分为 g c d ( d , i ) ≠ d gcd(d,i)\neq d gcd(d,i)̸=d的情况,那么容易发现后者的 μ \mu μ值均为 0 0 0,所以:
G ( i ∗ p r [ j ] ) = p r [ j ] ∗ i ∑ d ∣ i μ ( d ) d = p r [ j ] G ( i ) G(i*pr[j])=pr[j]*i\sum_{d|i}\mu(d)d=pr[j]G(i) G(ipr[j])=pr[j]idiμ(d)d=pr[j]G(i)

那么我们将 G G G函数线性筛出来之后,就可以将原始转变为:
∑ k = 1 n k ∑ d = 1 a μ ( d ) d 2 ∗ x ( x + 1 ) 2 ∗ y ( y + 1 ) x = ∑ t = 1 n f ( ⌊ n t ⌋ , ⌊ m t ⌋ ) G ( t ) \sum_{k=1}^{n}k\sum_{d=1}^{a}\mu(d)d^2*\frac{x(x+1)}{2}*\frac{y(y+1)}{x} =\sum_{t=1}^{n}f(\left \lfloor \frac{n}{t} \right \rfloor,\left \lfloor \frac{m}{t} \right \rfloor)G(t) k=1nkd=1aμ(d)d22x(x+1)xy(y+1)=t=1nf(tn,tm)G(t)

发现后面的式子在知道 G G G函数的取值时是可以用除法分块做到 O ( n ) O(\sqrt{n}) O(n )回答一次询问的.

那么我们只需要对 G G G函数进行线性筛并前缀和就可以做到 O ( n + T n ) O(n+T\sqrt{n}) O(n+Tn )解决这个问题了.

代码如下:

#include<bits/stdc++.h>
  using namespace std;
 
#define Abigail inline void
typedef long long LL;
 
const LL mod=100000009;      //把模数看成1e9+9死了一次...
const int N=10000000;
 
LL g[N+9];
int pr[N+9],b[N+9],tp;
 
LL M(LL x){
  x=x%mod+mod;
  return x>=mod?x-mod:x;
}
 
LL f(int x,int y){return M(M(LL(x+1)*x>>1)*M(LL(y+1)*y>>1));}
 
void sieve(int n){
  for (int i=2;i<=n;++i) b[i]=1;
  g[1]=1LL;
  for (int i=2;i<=n;++i){
    if (b[i]) pr[++tp]=i,g[i]=M(LL(1-i)*i);
    for (int j=1;j<=tp&&pr[j]*i<=n;++j){
      b[i*pr[j]]=0;
      if (i%pr[j]) g[i*pr[j]]=M(g[i]*g[pr[j]]);
      else {g[i*pr[j]]=M(g[i]*pr[j]);break;}
    }
  }
  for (int i=1;i<=n;++i)
    g[i]=M(g[i]+g[i-1]);
}
 
LL Query(int n,int m){
  if (n>m) swap(n,m);
  LL ans=0LL;
  for (int l=1,r;l<=n;l=r+1){
    r=min(n/(n/l),m/(m/l));
    ans=M(ans+f(n/l,m/l)*(g[r]-g[l-1]));
  }
  return ans;
} 
 
Abigail work(){
  sieve(N);
}
 
Abigail getans(){
  int T,n,m;
  scanf("%d",&T);
  while (T--){
    scanf("%d%d",&n,&m);
    printf("%lld\n",Query(n,m));
  }
}
 
int main(){
  work();
  getans();
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值