P4240 毒瘤之神的考验

毒瘤之神的考验

题意即求:

\[\sum _ { i = 1 } ^ {n} \sum _ { j = 1 } ^ { m } \varphi (ij) \pmod {9982443543} \]

其中 \(T\le 10 ^ 4\)\(n,m\le 10 ^ 5\)

我们尽量抛弃乘积的形式,将后面的 \(\varphi (ij)\) 转变为一个与 \(\gcd\) 有关的东西。

有结论:

\[\varphi ( i j ) = \dfrac {\varphi ( i ) \varphi ( j ) \gcd (i , j )} { \varphi ( \gcd ( i , j ))} \]

通过欧拉函数的计算式,读者自证不难。

开始推导:

\[\begin{aligned} & \sum _ { i = 1 } ^ {n} \sum _ { j = 1 } ^ { m } \varphi (ij) \\ = & \sum _ { i = 1 } ^ {n} \sum _ { j = 1 } ^ { m } \dfrac {\varphi ( i ) \varphi ( j ) \gcd (i , j )} { \varphi ( \gcd ( i , j ))} \\ = & \sum _ {d = 1} \sum _ { i = 1 } ^ {n} \sum _ { j = 1 } ^ { m } \left[ \gcd ( i ,j ) = d \right] \dfrac {\varphi ( i ) \varphi ( j ) d} { \varphi ( d )} \\ = & \sum _ {d = 1} \dfrac{d}{\varphi(d)}\sum _ { i = 1 } ^ {\left\lfloor n / d\right\rfloor} \sum _ { j = 1 } ^ { \left\lfloor m / d\right\rfloor } \varphi ( id ) \varphi ( jd ) \left[ \gcd ( i ,j ) = 1 \right] \\ = & \sum _ {d = 1} \dfrac{d}{\varphi(d)}\sum _ { i = 1 } ^ {\left\lfloor n / d\right\rfloor} \sum _ { j = 1 } ^ { \left\lfloor m / d\right\rfloor } \varphi ( id ) \varphi ( jd ) \sum _ { k \mid i,k \mid j} \mu (k) \\ = & \sum _ {d = 1} \dfrac{d}{\varphi(d)} \sum _ { k = 1 } \mu (k) \sum _ { i = 1 } ^ {\left\lfloor n / kd\right\rfloor} \varphi ( ikd ) \sum _ { j = 1 } ^ { \left\lfloor m / kd\right\rfloor } \varphi ( jkd ) \\ = & \sum _ { T = 1 } \sum _ {d \mid T } \dfrac{d}{\varphi(d)} \mu \left(\dfrac{T}{d}\right) \sum _ { i = 1 } ^ {\left\lfloor n / T\right\rfloor} \varphi ( iT ) \sum _ { j = 1 } ^ { \left\lfloor m / T\right\rfloor } \varphi ( jT ) \end{aligned} \]

没有办法整除分块。考虑值域平衡的策略。

定义 \(F(x,d) = \sum _ { i = 1 } ^ { x } \varphi (id)\)

根据 \(xd\le n\),可以知道 \(F(x,d)\) 的数量在 \(O(n \ln n)\),借助一个 vector 就可以完成预处理,且其求取也可以在 \(O(n \ln n)\) 下完成。

现在定义:

\[G(x,y,z) = \sum _ { T = 1 } ^ {z} \sum _ {d \mid T } \dfrac{d}{\varphi(d)} \mu \left(\dfrac{T}{d}\right) \sum _ { i = 1 } ^ {x} \varphi ( iT ) \sum _ { j = 1 } ^ { y } \varphi ( jT ) \]

我们对 \(x,y\le B\) 的这部分 \(G(x,y,z)\) 进行预处理,数量是 \(O(n B ^ 2)\) 的,时间复杂度也是 \(O (n B ^ 2 )\) 的。

看起来很奇怪,但是我们借助整除分块,会有如下结论:

\[\begin{aligned} & \sum _ { T = 1 } \sum _ {d \mid T } \dfrac{d}{\varphi(d)} \mu \left(\dfrac{T}{d}\right) \sum _ { i = 1 } ^ {\left\lfloor n / T\right\rfloor} \varphi ( iT ) \sum _ { j = 1 } ^ { \left\lfloor m / T\right\rfloor } \varphi ( jT ) \\ = & \sum _ { l , r } G(\left\lfloor n / l\right\rfloor,\left\lfloor m / l\right\rfloor,r) - G (\left\lfloor n / l\right\rfloor,\left\lfloor m / l\right\rfloor,l-1) \end{aligned} \]

(不想多次说明,以下语句中,表示时间复杂度的 \(T\) 都是数据组数;其余的 \(T\) 即为计算式中的变量)

其中 \([l,r]\) 表示整除分块中一个 \(\left\lfloor n / l\right\rfloor = \left\lfloor m / l\right\rfloor\) 的块。

这样,我们对于 \(\left\lfloor n / T\right\rfloor \le B\) 的部分就可以通过 \(G\) 来解决,时间复杂度自然是 \(O(T \sqrt{n})\) 的。

而对于 \(\left\lfloor n / T\right\rfloor > B\) 的情况,我们知道肯定有 \(T \le \left\lfloor n / B\right\rfloor\),这个时候针对每个 \(T\),根据原式暴力计算即可。这一部分的时间复杂度是 \(O(Tn/B)\) 的。

最后我们的总的时间复杂度是 \(O(n\ln n + T \sqrt{n} + n B ^ 2 + T n / B)\) 的。

值域平衡一下,可以得到 \(B = T ^{1/3}\)

最后的时间复杂度就是 \(O(n\ln n + T \sqrt{n} + T ^{2/3}n)\)

代码中对于 \(\sum _ {d\mid T} \mu (T/d) d / \varphi (d)\) 的计算方式是对 \(h(d) = d/ \varphi (d)\) 进行 \(\mu\) 变换得到的。对其方式有不解可以去找我的关于 Direchlet 前缀和的讲解。

代码:

#include<iostream>
#include<cstdio>
#include<vector>
#define ll long long
using namespace std;
namespace Ehnaev{
  inline ll read() {
    ll ret=0,f=1;char ch=getchar();
    while(ch<48||ch>57) {if(ch==45) f=-f;ch=getchar();}
    while(ch>=48&&ch<=57) {ret=(ret<<3)+(ret<<1)+ch-48;ch=getchar();}
    return ret*f;
  }
  inline void write(ll x) {
    static char buf[22];static ll len=-1;
    if(x>=0) {do{buf[++len]=x%10+48;x/=10;}while(x);}
    else {putchar(45);do{buf[++len]=-(x%10)+48;x/=10;}while(x);}
    while(len>=0) putchar(buf[len--]);
  }
}using Ehnaev::read;using Ehnaev::write;
inline void writeln(ll x) {write(x);putchar(10);}

const ll mo=998244353,N=1e5,B=30;

ll T,n,m,ans,cnt;
ll phi[N+5],h[N+5],prime[N+5],inv[N+5];
ll g[B+5][B+5][N+5];
bool ff[N+5];
vector<ll> f[N+5];

inline void Init() {
  ff[1]=1;phi[1]=1;
  for(ll i=2;i<=N;i++) {
    if(!ff[i]) {prime[++cnt]=i;phi[i]=i-1;}
    for(ll j=1;j<=cnt&&i*prime[j]<=N;j++) {
      ff[i*prime[j]]=1;
      if(i%prime[j]==0) {
        phi[i*prime[j]]=phi[i]*prime[j]%mo;
        break;
      }
      phi[i*prime[j]]=phi[i]*phi[prime[j]]%mo;
    }
  }
  inv[1]=1;
  for(ll i=2;i<=N;i++) {inv[i]=(mo-mo/i)*inv[mo%i]%mo;}
  for(ll i=1;i<=N;i++) {h[i]=i*inv[phi[i]]%mo;}
  for(ll i=1;i<=cnt;i++) {
    for(ll j=N/prime[i];j;j--) {
      h[j*prime[i]]=(h[j*prime[i]]-h[j]+mo)%mo;
    }
  }
  for(ll i=0;i<=N;i++) f[0].push_back(0);
  for(ll i=1;i<=N;i++) f[i].push_back(0);
  for(ll i=1;i<=N;i++) {
    for(ll j=i,cn=1;j<=N;j+=i,cn++) {
      f[cn].push_back((f[cn-1][i]+phi[j])%mo);
    }
  }
  for(ll i=1;i<=B;i++) {
    for(ll j=1;j<=B;j++) {
      for(ll k=1;k*i<=N&&k*j<=N;k++) {
        ll tmp=(h[k]*f[i][k]%mo)*f[j][k]%mo;
        g[i][j][k]=(g[i][j][k]+tmp)%mo;
      }
    }
  }
  for(ll i=1;i<=B;i++) {
    for(ll j=1;j<=B;j++) {
      for(ll k=1;k*i<=N&&k*j<=N;k++) {
        g[i][j][k]=(g[i][j][k]+g[i][j][k-1])%mo;
      }
    }
  }
}

int main() {

  T=read();Init();

  while(T--) {
    n=read();m=read();if(n<m) swap(n,m);
    ans=0;
    for(ll i=1;i*B<=n;i++) {
      ll tmp=(h[i]*f[n/i][i]%mo)*f[m/i][i]%mo;
      ans=(ans+tmp)%mo;
    }
    for(ll i=n/B+1,j;i<=m;i=j+1) {
      j=min(n/(n/i),m/(m/i));
      ll tmp=(g[n/i][m/i][j]-g[n/i][m/i][i-1]+mo)%mo;
      ans=(ans+tmp)%mo;
    }
    writeln(ans);
  }

  return 0;
}
posted @ 2023-02-06 15:17  Aryper  阅读(30)  评论(0编辑  收藏  举报