题解 P4240【毒瘤之神的考验】

简化题面

\[\sum_{i=1}^n\sum_{j=1}^m\varphi{(i\times j)} \]

答案对\(998244353\)取模。多组询问

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

解题思路

这题在我计划里面躺了最少有五个月了,当时觉得好难啊就没做= =,最近拿出来看看好简单啊于是就做了

考虑大力推柿子

对于\(\varphi{(i\times j)}\),我们有一个不是很显然的也不是很常见的结论,

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

考虑如何证明,我们将\(\varphi\)都用定义拆开,可以写成比较鬼畜的形式

\[i\times j\prod_{p|i\ or j} \frac{p-1}{p}=\frac{i\prod_{p|i} \frac{p-1}{p} j\prod_{p|j} \frac{p-1}{p}gcd(i,j)}{gcd(i,j)\prod_{p|i\ and j} \frac{p-1}{p}} \]

显然两边是相等的。

那么既然已经知道了这玩意那我们直接就可以做了

\[\sum_{i=1}^n\sum_{j=1}^m \frac{\varphi{(i)}\times \varphi{(j)}\times gcd(i,j)}{\varphi{(gcd(i,j))}} \]

\[=\sum_{p=1}^n \frac{p}{\varphi{(p)}}\sum_{i=1}^n\sum_{j=1}^m \varphi{(i)}\varphi{(j)} [gcd(i,j)=p] \]

\[=\sum_{p=1}^n \frac{p}{\varphi{(p)}} \sum_{i=1}^{\frac{n}{p}}\sum_{j=1}^{\frac{m}{p}} \varphi{(ip)}\varphi{(jp)} [gcd(i,j)=1] \]

\[=\sum_{p=1}^n \frac{p}{\varphi{(p)}} \sum_{i=1}^{\frac{n}{p}}\sum_{j=1}^{\frac{m}{p}} \varphi{(ip)}\varphi{(jp)} \sum_{d|i,j}\mu{(d)} \]

\[=\sum_{p=1}^n \frac{p}{\varphi{(p)}} \sum_{d=1}^n \mu{(d)} \sum_{i=1}^{\frac{n}{dp}}\sum_{j=1}^{\frac{m}{dp}} \varphi{(idp)}\varphi{(jdp)} \]

\[=\sum_{Q=1}^n \sum_{p|Q} \frac{p\mu{(\frac{Q}{p})}}{\varphi{(p)}} \sum_{i=1}^{\frac{n}{Q}} \varphi{(iQ)}\sum_{j=1}^{\frac{m}{Q}}\varphi{(jQ)} \]

显然到这里没办法继续推了,考虑如何进行预处理。

第一部分显然可以在\(O(nlogn)\)的时间内进行预处理得到

那么考虑如何处理后面的玩意,我们令\(g(k,n)=\sum_{i=1}^n \varphi{(i\times k)}\),这个玩意显然是可以递推的\(g(i,j)=g(i,j-1)+\varphi{(i\times j)}\)

于是这个玩意又可以在\(O(nlogn)\)的时间复杂度内预处理出来

那么原柿子现在变成了

\[\sum_{Q=1}^n \sum_{p|Q} \frac{p\mu{(\frac{Q}{p})}}{\varphi{(p)}} g(Q,\frac{n}{Q}) g(Q,\frac{m}{Q}) \]

那么到这里一个很自然的想法是我们可以进行分块打表预处理

考虑设\(t(i,j,Q)\),前面的\(i,j\)是分别处于的块\(\frac{n}{Q}\)\(\frac{m}{Q}\),这个玩意还是可以递推的\(t(i,j,Q)=t(i,j,Q-1)+\sum_{p|Q} \frac{p\mu{(\frac{Q}{p})}}{\varphi{(p)}} g(Q,i) g(Q,j)\)

我们直接设定大小为\(len\)的块暴力\(O(n^2)\)预处理就可以了,最后统计答案的时候散块暴力整块直接分块统计答案就可以了。

时间复杂度是\(O(nlogn+nlen^2+T(\sqrt n+\frac{n}{len}))\)

\(\mathcal{Code}\)

// Author: Ame__
#include<bits/stdc++.h>
#include<stdint.h>
#define _ 0
#define AME__DEBUG
#define bomb exit(0)
#define LOG(FMT...) fprintf(stderr , FMT)
#define TOWA(FMT...) fprintf(stdout , FMT)
using namespace std;
/*Grievous Lady*/
    
typedef int32_t i32;
typedef int64_t i64;
typedef double qwq;
    
const int BUF_SIZE = 1 << 12;
char buf[BUF_SIZE] , *buf_s = buf , *buf_t = buf + 1;
    
#define PTR_NEXT() \
{ \
    buf_s ++; \
    if(buf_s == buf_t) \
    { \
        buf_s = buf; \
        buf_t = buf + fread(buf , 1 , BUF_SIZE , stdin); \
    } \
}
    
#define mians(_s_) \
{ \
    while(!isgraph(*buf_s)) PTR_NEXT();\
    char register *_ptr_ = (_s_); \
    while(isgraph(*buf_s) || *buf_s == '-') \
    { \
        *(_ptr_ ++) = *buf_s; \
        PTR_NEXT(); \
    } \
    (*_ptr_) = '\0'; \
}
    
template <typename _n_> void mian(_n_ & _x_){
    while(*buf_s != '-' && !isdigit(*buf_s)) PTR_NEXT();
    bool register _nega_ = false; if(*buf_s == '-'){ _nega_ = true; PTR_NEXT(); }
    _x_ = 0; while(isdigit(*buf_s)){ _x_ = _x_ * 10 + *buf_s - '0'; PTR_NEXT(); } if(_nega_) _x_ = -_x_;
}
    
const i32 kato = 1e5 + 10;
const i32 atri = 1e5;
const i32 deco = 1e2 + 10;
const i32 mod = 998244353;

template <typename _n_> bool cmax(_n_ &a , const _n_ &b){ return a < b ? a = b , 1 : 0; }
template <typename _n_> bool cmin(_n_ &a , const _n_ &b){ return a > b ? a = b , 1 : 0; }
    
i32 prime[kato] , phi[kato] , mu[kato] , inv[kato] , sum[kato];
bool ispri[kato];
i32 n , m , cnt , T , b = 50;
i32 *g[kato] , *t[deco][deco];

inline i32 quick_pow(i32 a , i32 b){
    i32 res = 1;
    for(; b ; b >>= 1 , a = static_cast<i64>(a) * a % mod){
        if(b & 1){
            res = static_cast<i64>(res) * a % mod;
        }
    }
    return res;
}

inline void pri(){
    for(i32 i = 2;i <= atri;i ++){
        if(!ispri[i]){
            prime[++ cnt] = i;
            phi[i] = i - 1;
            mu[i] = -1;
        }
        for(i32 j = 1;j <= cnt && i * prime[j] <= atri;j ++){
            ispri[i * prime[j]] = 1;
            if(i % prime[j] == 0){
                phi[i * prime[j]] = phi[i] * prime[j];
                break;
            }
            phi[i * prime[j]] = phi[i] * phi[prime[j]];
            mu[i * prime[j]] = -mu[i];
        }
        inv[i] = quick_pow(phi[i] , mod - 2);
    }
    for(i32 i = 1;i <= atri;i ++){
        for(i32 j = i , d = 1;j <= atri;j += i , d ++) sum[j] = ((sum[j] + static_cast<i64>(i) * inv[i] % mod * mu[d] % mod) + mod) % mod;
    }
    for(i32 i = 1;i <= atri;i ++){
        g[i] = new i32[atri / i + 10] , g[i][0] = 0;
        for(i32 j = 1;j <= atri / i;j ++) g[i][j] = (g[i][j - 1] + phi[i * j]) % mod;
    }
    for(i32 i = 1;i <= b;i ++){
        for(i32 j = i;j <= b;j ++){
            i32 len = atri / max(i , j);
            t[i][j] = new i32[len + 10] , t[i][j][0] = 0;
            for(i32 k = 1;k <= len;k ++) t[i][j][k] = (t[i][j][k - 1] + static_cast<i64>(sum[k]) * g[k][i] % mod * g[k][j] % mod) % mod;
        }
    }
}

inline int Ame_(){
#ifdef AME__
    freopen(".in" , "r" , stdin); freopen(".out" , "w" , stdout); int nol_cl = clock();
#endif
    mian(T); phi[1] = mu[1] = inv[1] = 1; pri();
    for(; T --> 0 ;){
        mian(n) , mian(m);
        if(n > m) swap(n , m);
        i32 ans = 0;
        for(i32 i = 1;i <= m / b;i ++) ans = (ans + static_cast<i64>(sum[i]) * g[i][n / i] % mod * g[i][m / i] % mod) % mod;
        for(i32 l = m / b + 1 , r;l <= n;l = r + 1){
            r = min(n / (n / l) , m / (m / l));
            ans = ((ans + t[n / l][m / l][r] - t[n / l][m / l][l - 1]) % mod + mod) % mod;
        }
        TOWA("%d\n" , ans);
    }
#ifdef AME__TIME
    LOG("Time: %dms\n", int((clock() - nol_cl) / (qwq)CLOCKS_PER_SEC * 1000));
#endif
    return ~~(0^_^0); /*さようならプログラム*/
}
    
int Ame__ = Ame_();
    
int main(){;}
posted @ 2021-03-10 15:17  Ame_sora  阅读(65)  评论(0编辑  收藏  举报