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


    简化题面

    [sum_{i=1}^nsum_{j=1}^mvarphi{(i imes j)} ]

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

    (1le Tle 10^4)(1le n,mle 10^5)

    解题思路

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

    考虑大力推柿子

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

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

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

    [i imes jprod_{p|i or j} frac{p-1}{p}=frac{iprod_{p|i} frac{p-1}{p} jprod_{p|j} frac{p-1}{p}gcd(i,j)}{gcd(i,j)prod_{p|i and j} frac{p-1}{p}} ]

    显然两边是相等的。

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

    [sum_{i=1}^nsum_{j=1}^m frac{varphi{(i)} imes varphi{(j)} imes gcd(i,j)}{varphi{(gcd(i,j))}} ]

    [=sum_{p=1}^n frac{p}{varphi{(p)}}sum_{i=1}^nsum_{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{pmu{(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 imes k)}),这个玩意显然是可以递推的(g(i,j)=g(i,j-1)+varphi{(i imes j)})

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

    那么原柿子现在变成了

    [sum_{Q=1}^n sum_{p|Q} frac{pmu{(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{pmu{(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_) = ''; 
    }
        
    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
    " , ans);
        }
    #ifdef AME__TIME
        LOG("Time: %dms
    ", int((clock() - nol_cl) / (qwq)CLOCKS_PER_SEC * 1000));
    #endif
        return ~~(0^_^0); /*さようならプログラム*/
    }
        
    int Ame__ = Ame_();
        
    int main(){;}
    
    呐,这份感情,什么时候可以传达呢
  • 相关阅读:
    求助 大家帮忙激励下我吧
    实体培训,特别是对于学历教育中教学理论的一些总结
    天轰穿c#趣味编程系列视频 vs2005/2008 winform实例入门 第二集 学习技巧风暴
    感谢老婆的支持我永远爱你,亲爱的梅
    早上起床晚了,差点迟到,两集视频已经做好
    我带这个班最近两次的作业
    辛辛苦苦几十年,一朝回到解放前我以及我的部分亲人都平安
    天轰穿c#趣味编程系列视频 vs2005/2008 winform实例入门 第一集
    如果有媒体的朋友建议看下这个帖子
    无聊的盗版问题
  • 原文地址:https://www.cnblogs.com/Ame-sora/p/14511885.html
Copyright © 2020-2023  润新知