luogu p4240 毒瘤之神的考验

亡梦爱人 提交于 2019-11-30 19:48:37

题意 : 求 $\sum_{i=1}^{N}{\sum_{j=1}^{M}{\phi(ij)}}; N,M \leq 10^5, q \leq 10^4$

设 $N \leq M$.

根据$\phi$的性质 可以得到$\phi(ij)=\frac{\phi(i)\phi(j)gcd(i,j)}{\phi(gcd(i,j))}$

如果这一步没想到,只能说是莫反做的不够多了...

$nm$过大的情况下是没法处理乘积的,而且直接这么看也看不出什么性质来

所以考虑把乘在一起的$ij$分开处理。

于是 $\sum_{i=1}^{N}{\sum_{j=1}^{M}{\phi(ij)}} = \sum_{i=1}^{N}{\sum_{j=1}^{M}{\frac{\phi(i)\phi(j)gcd(i,j)}{\phi(gcd(i,j))}}}$,

将$gcd(i,j)$相关提出来 可以得到

$\sum_{i=1}^{N}{\sum_{j=1}^{M}{\frac{\phi(i)\phi(j)gcd(i,j)}{\phi(gcd(i,j))}}}=\sum_{d=1}^{N}{\frac{d}{\phi(d)}\sum_{i=1}^{N/d}{\sum_{j=1}^{M/d}{\phi(id)\phi(jd)}{\sum_{e|gcd(i,j)}{\mu(e)}}}}$

常规性地开始枚举$e$ 得到 $\sum_{d=1}^{N}{\frac{d}{\phi(d)}\sum_{e=1}^{N/d}{\mu(e){\sum_{i=1}^{N/de}{\sum_{j=1}^{M/de}{\phi(ide)\phi(jde)}}}}}$

习惯性地枚举$de$ 得到 $\sum_{T=1}^{N}{\sum_{i=1}^{N/T}{\phi(iT)\sum_{j=1}^{M/T}{\phi(jT)}}\sum_{d|T}{\phi(\frac{T}{d})\frac{d}{\phi(d)}}}$

设$f(T)=\sum_{d|T}{\phi(\frac{T}{d})\frac{d}{\phi(d)}}$ , $G(N,T)=\sum_{i=1}^{N}{\phi(iT)}$, 代入上式得 :

$\sum_{T=1}^{N}{\sum_{i=1}^{N/T}{\phi(iT)\sum_{j=1}^{M/T}{\phi(jT)}}\sum_{d|T}{\phi(\frac{T}{d})\frac{d}{\phi(d)}}}=\sum_{T=1}^{N}{G(N/T,T)G(M/T,T)f(T)}$

设 $S(n,i,j)=\sum_{T=1}^{n}G(iT,T)G(jT,T)f(T)$

那么设$\lfloor{N/T}\rfloor==i,\lfloor{M/T}\rfloor==j$时$N$的最大值为$up$,最小值为$down$ 那么

此时的$ans=S(up,i,j) - S(down-1,i,j)$

因为上界是$\lfloor{N/T}\rfloor$所以$G$可以用$NlnN$内全部暴力预处理出来

$G(N,T)=G(N-1,T)+\phi(NT)$

可以预处理一部分$S$, 其中$S(N,i,j)=S(N-1,i,j)+G(iN,N)G(jN,N)f(N)$

经过计算(调参)可以得到上界$B$

upd :为啥代码丢到LOJ上就挂的只剩下50了 , 求助。

#include<cstdio>
#include<cstring>
#include<vector>

const int N = 1e5 + 7;
const int lim = 1e5;
const int B = 35;
typedef long long ll;
const int p = 998244353;
inline int max (int a, int b) {
  return a > b ? a : b;
}
inline int min (int a, int b) {
  return a > b ? b : a;
}

int isp[N], mu[N], phi[N], prime[N], pcnt;
int *G[N], *S[B + 1][B + 1], f[N], inv[N];

inline void init () {
  inv[1] = 1, mu[1] = 1, phi[1] = 1;
  for (int i = 2; i <= lim; i++) inv[i] = p - (ll)(p / i) * inv[p % i] % p;
  for (int i = 2; i <= lim; i++) {
    if (!isp[i]) phi[i] = i - 1, mu[i] = -1, prime[++pcnt] = i;
    for (int j = 1; j <= pcnt && prime[j] * i <= lim; j++) {
      isp[i * prime[j]] = 1;
      if (i % prime[j] == 0) {
        phi[i * prime[j]] = phi[i] * prime[j] % p, mu[i * prime[j]] = 0;
        break;
      }
      phi[i * prime[j]] = phi[i] * (prime[j] - 1) % p , mu[i * prime[j]] = -mu[i];
    }
  }
  for (int i = 1; i <= lim; i++) for (int j = 1; i * j <= lim; j++) {
      f[i * j] = (f[i * j] + (ll) ((ll)i * inv[phi[i]] % p) % p * mu[j] % p) % p;
    }
  for (int i = 1; i <= lim; i++) {
    int upmax = lim / i;
    G[i] = new int [upmax + 1];
    G[i][0] = 0;
    for (int j = 1; j <= upmax; j++) G[i][j] = (ll)((ll)G[i][j - 1] + (ll)phi[i * j]) % p;
  }
  for (int j = 1; j <= B; j++) for (int k = 1; k <= B; k++) {
      int upmax = (lim / max (j, k));
      S[j][k] = new int [upmax + 1];
      S[j][k][0] = 0;
      for (int i = 1; i <= upmax; i++) {
        S[j][k][i] = (ll)((ll)S[j][k][i - 1] + ll((ll)f[i] * G[i][j] % p * G[i][k])) % p;
      }
    }
}
int main () {
  int T;
  scanf ("%d", &T);
  init ();
  while (T--) {
    int n, m, tmp;
    scanf ("%d%d", &n, &m);
    if (n > m) tmp = n, n = m, m = tmp;
    ll ans = 0;
    for (int i = 1, upmax = m / B; i <= upmax; i++)
      ans = (ans + ((ll)f[i] * G[i][n / i] % p * G[i][m / i] % p)) % p;
    for (int l = m / B + 1, r; l <= n; l = r + 1) {
      r = min (n / (n / l), m / (m / l));
      ans = (ans + (ll(S[n / l][m / l][r] - S[n / l][m / l][l - 1]) % p + p) % p) % p;
    }
    printf ("%lld\n", ans);
  }
  return 0;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!