SPOJ 5971 LCM SUM

转载自 OI-Wiki

「SPOJ 5971」LCMSUM

求值(多组数据)

∑ i = 1 n lcm ⁡ ( i , n ) s.t.  1 ⩽ T ⩽ 3 × 1 0 5 , 1 ⩽ n ⩽ 1 0 6 \sum_{i=1}^n \operatorname{lcm}(i,n)\quad \text{s.t.}\ 1\leqslant T\leqslant 3\times 10^5,1\leqslant n\leqslant 10^6 i=1nlcm(i,n)s.t. 1T3×105,1n106

易得原式即

∑ i = 1 n i ⋅ n gcd ⁡ ( i , n ) \sum_{i=1}^n \frac{i\cdot n}{\gcd(i,n)} i=1ngcd(i,n)in

将原式复制一份并且颠倒顺序,然后将 n 一项单独提出,可得

1 2 ⋅ ( ∑ i = 1 n − 1 i ⋅ n gcd ⁡ ( i , n ) + ∑ i = n − 1 1 i ⋅ n gcd ⁡ ( i , n ) ) + n \frac{1}{2}\cdot \left(\sum_{i=1}^{n-1}\frac{i\cdot n}{\gcd(i,n)}+\sum_{i=n-1}^{1}\frac{i\cdot n}{\gcd(i,n)}\right)+n 21(i=1n1gcd(i,n)in+i=n11gcd(i,n)in)+n

根据 gcd ⁡ ( i , n ) = gcd ⁡ ( n − i , n ) \gcd(i,n)=\gcd(n-i,n) gcd(i,n)=gcd(ni,n),可将原式化为

1 2 ⋅ ( ∑ i = 1 n − 1 i ⋅ n gcd ⁡ ( i , n ) + ∑ i = n − 1 1 i ⋅ n gcd ⁡ ( n − i , n ) ) + n \frac{1}{2}\cdot \left(\sum_{i=1}^{n-1}\frac{i\cdot n}{\gcd(i,n)}+\sum_{i=n-1}^{1}\frac{i\cdot n}{\gcd(n-i,n)}\right)+n 21(i=1n1gcd(i,n)in+i=n11gcd(ni,n)in)+n

两个求和式中分母相同的项可以合并。

1 2 ⋅ ∑ i = 1 n − 1 n 2 gcd ⁡ ( i , n ) + n \frac{1}{2}\cdot \sum_{i=1}^{n-1}\frac{n^2}{\gcd(i,n)}+n 21i=1n1gcd(i,n)n2+n

1 2 ⋅ ∑ i = 1 n n 2 gcd ⁡ ( i , n ) + n 2 \frac{1}{2}\cdot \sum_{i=1}^{n}\frac{n^2}{\gcd(i,n)}+\frac{n}{2} 21i=1ngcd(i,n)n2+2n

可以将相同的 gcd ⁡ ( i , n ) \gcd(i,n) gcd(i,n) 合并在一起计算,故只需要统计 gcd ⁡ ( i , n ) = d \gcd(i,n)=d gcd(i,n)=d 的个数。当 gcd ⁡ ( i , n ) = d \gcd(i,n)=d gcd(i,n)=d 时, gcd ⁡ ( i d , n d ) = 1 \displaystyle\gcd(\frac{i}{d},\frac{n}{d})=1 gcd(di,dn)=1,所以 gcd ⁡ ( i , n ) = d \gcd(i,n)=d gcd(i,n)=d 的个数有 φ ( n d ) \displaystyle\varphi(\frac{n}{d}) φ(dn) 个。

故答案为

1 2 ⋅ ∑ d ∣ n n 2 ⋅ φ ( n d ) d + n 2 \frac{1}{2}\cdot\sum_{d\mid n}\frac{n^2\cdot\varphi(\frac{n}{d})}{d}+\frac{n}{2} 21dndn2φ(dn)+2n

变换求和顺序,设 d ′ = n d \displaystyle d'=\frac{n}{d} d=dn,合并公因式,式子化为

1 2 n ⋅ ( ∑ d ′ ∣ n d ′ ⋅ φ ( d ′ ) + 1 ) \frac{1}{2}n\cdot\left(\sum_{d'\mid n}d'\cdot\varphi(d')+1\right) 21ndndφ(d)+1

g ⁡ ( n ) = ∑ d ∣ n d ⋅ φ ( d ) \displaystyle \operatorname{g}(n)=\sum_{d\mid n} d\cdot\varphi(d) g(n)=dndφ(d),已知 g ⁡ \operatorname{g} g 为积性函数,于是可以 Θ ( n ) \Theta(n) Θ(n) 筛出。每次询问 Θ ( 1 ) \Theta(1) Θ(1) 计算即可。

下面给出这个函数筛法的推导过程:

首先考虑 g ⁡ ( p j k ) \operatorname g(p_j^k) g(pjk) 的值,显然它的约数只有 p j 0 , p j 1 , ⋯   , p j k p_j^0,p_j^1,\cdots,p_j^k pj0,pj1,,pjk,因此

g ⁡ ( p j k ) = ∑ w = 0 k p j w ⋅ φ ( p j w ) \operatorname g(p_j^k)=\sum_{w=0}^{k}p_j^w\cdot\varphi(p_j^w) g(pjk)=w=0kpjwφ(pjw)

又有 φ ( p j w ) = p j w − 1 ⋅ ( p j − 1 ) \varphi(p_j^w)=p_j^{w-1}\cdot(p_j-1) φ(pjw)=pjw1(pj1),则原式可化为

∑ w = 0 k p j 2 w − 1 ⋅ ( p j − 1 ) \sum_{w=0}^{k}p_j^{2w-1}\cdot(p_j-1) w=0kpj2w1(pj1)

于是有

g ⁡ ( p j k + 1 ) = g ⁡ ( p j k ) + p j 2 k + 1 ⋅ ( p j − 1 ) \operatorname g(p_j^{k+1})=\operatorname g(p_j^k)+p_j^{2k+1}\cdot(p_j-1) g(pjk+1)=g(pjk)+pj2k+1(pj1)

那么,对于线性筛中的 g ⁡ ( i ⋅ p j ) ( p j ∣ i ) \operatorname g(i\cdot p_j)(p_j|i) g(ipj)(pji),令 i = a ⋅ p j w ( gcd ⁡ ( a , p j ) = 1 ) i=a\cdot p_j^w(\operatorname{gcd}(a,p_j)=1) i=apjw(gcd(a,pj)=1),可得

g ⁡ ( i ⋅ p j ) = g ⁡ ( a ) ⋅ g ⁡ ( p j w + 1 ) \operatorname g(i\cdot p_j)=\operatorname g(a)\cdot\operatorname g(p_j^{w+1}) g(ipj)=g(a)g(pjw+1)

g ⁡ ( i ) = g ⁡ ( a ) ⋅ g ⁡ ( p j w ) \operatorname g(i)=\operatorname g(a)\cdot\operatorname g(p_j^w) g(i)=g(a)g(pjw)

g ⁡ ( i ⋅ p j ) − g ⁡ ( i ) = g ⁡ ( a ) ⋅ p j 2 w + 1 ⋅ ( p j − 1 ) \operatorname g(i\cdot p_j)-\operatorname g(i)=\operatorname g(a)\cdot p_j^{2w+1}\cdot(p_j-1) g(ipj)g(i)=g(a)pj2w+1(pj1)

同理有

g ⁡ ( i ) − g ⁡ ( i p j ) = g ⁡ ( a ) ⋅ p j 2 w − 1 ⋅ ( p j − 1 ) \operatorname g(i)-\operatorname g(\frac{i}{p_j})=\operatorname g(a)\cdot p_j^{2w-1}\cdot(p_j-1) g(i)g(pji)=g(a)pj2w1(pj1)

因此

g ⁡ ( i ⋅ p j ) = g ⁡ ( i ) + ( g ⁡ ( i ) − g ⁡ ( i p j ) ) ⋅ p j 2 \operatorname g(i\cdot p_j)=\operatorname g(i)+\left (\operatorname g(i)-\operatorname g(\frac{i}{p_j})\right )\cdot p_j^2 g(ipj)=g(i)+(g(i)g(pji))pj2

时间复杂度 Θ ( n + T ) \Theta(n+T) Θ(n+T)

代码

#include <cstdio>
const int N = 1000000;
int tot, p[N + 5];
long long g[N + 5];
bool flg[N + 5];  //标记数组

void solve() {
  g[1] = 1;
  for (int i = 2; i <= N; ++i) {
    if (!flg[i]) {
      p[++tot] = i;
      g[i] = (long long)1 * i * (i - 1) + 1;
    }
    for (int j = 1; j <= tot && i * p[j] <= N; ++j) {
      flg[i * p[j]] = 1;
      if (i % p[j] == 0) {
        g[i * p[j]] =
            g[i] + (g[i] - g[i / p[j]]) * p[j] * p[j];  //代入推出来的式子
        break;
      }
      g[i * p[j]] = g[i] * g[p[j]];
    }
  }
}
int main() {
  int T, n;
  solve();  //预处理g数组
  scanf("%d", &T);
  for (int i = 1; i <= T; ++i) {
    scanf("%d", &n);
    printf("%lld\n", (g[n] + 1) * n / 2);
  }
  return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值