[FJWC2020] lg

首先对\(\operatorname{lcm}\)按各个质因子的贡献处理。

设当前质因子为\(p^q\),需要计算出\(\operatorname{lcm}\)\(p^q\)\(\gcd\)和。

这里计算\(\operatorname{lcm}\)恰好含有\(p^q\)的不方便,可以设\(\operatorname{lcm}\)\(p\)的指数小于\(q\)的进行求和,然后转化成\(x_i\)不能是\(p^q\)的倍数。

然后设\(\gcd\)\(p\)质因子含有\(p^a\),则剩余部分\(\gcd\)不能出现\(p\)的倍数,也不能有数达到\(p^{q-a}\)

按照套路,可以枚举所有数都是是\(T\)的倍数的组数\(S\)\(\gcd\)和就是\(\sum S \cdot \varphi(T)\),因为\(\varphi * \mathbf{I} = \mathbf{id}\),每个\(\gcd\)都会在它的约数处被统计一次,也可以用 Mobius 反演证。

最后就是要设法统计出不是\(p\)的倍数的数的个数。显然\(T \nmid p\),把不合法的减掉就好。还要满足不能每个数都是\(p\)的倍数,因此要减掉约掉\(T\)\(\gcd\)仍含\(p\)的倍数的,于是式子:(设\(N = \lfloor \dfrac{m}{p^a} \rfloor\)),以下都是整除:

\[ \sum_{T=1}^N\Big(({N \over T} - {N \over Tp^{q-a}})^n - ({N \over Tp} - {N \over Tp^{q-a}})^n\Big) \varphi(T) \]

最后统计答案即可。

这里全部使用整除分块实现,复杂度\(\mathcal O(n \log \log n + N\sqrt N)\),其中\(\sqrt N\)上不带任何\(\log\)可以用等比数列求和分析出。

Code

#include <cstdio>
#include <algorithm>
#include <cassert>
using namespace std;
#define File(s) freopen(s".in", "r", stdin), freopen(s".out", "w", stdout)
typedef long long ll;

const int M = 200005, mod = 998244353, mod1 = 998244352;
int pown[M];
template<int mod>
inline int power(int x, int y){
    int res = 1;
    for(; y; y>>=1, x = (1LL * x * x) % mod) if(y & 1) res = (1LL * res * x) % mod;
    return res;
}

bool np[M];
int pr[M], phi[M], pc = 0;
int phiMp[M];
void primeList(int n){
    phi[1] = 1;
    for(int i=2; i<=n; i++){
        if(!np[i]) pr[++pc] = i, phi[i] = i - 1;
        for(int j=1; j<=pc && i * pr[j] <= n; j++){
            np[i * pr[j]] = true;
            if(i % pr[j] == 0){
                phi[i * pr[j]] = phi[i] * pr[j];
                break;
            }
            phi[i * pr[j]] = phi[i] * (pr[j] - 1);
        }
    }
    for(int i=2; i<=n; i++) phi[i] = (phi[i] + phi[i-1]) % mod1;
}

int main(){
    int n, m;
    scanf("%d%d", &n, &m);
    for(int i=1; i<=m; i++) pown[i] = power<mod1>(i, n);
    primeList(m);
    int res = 1;
    int compGCD = 0;
    for(int l=1, r; l<=m; l=r+1){
        r = m / (m / l);
        compGCD = (compGCD + 1LL * pown[m / l] * (mod1 + phi[r] - phi[l - 1]) % mod1) % mod1;
    }
    for(int i=1; i<=pc; i++){
        int p = pr[i];
        for(int j=1; j<=m/p; j++)
            phiMp[j] = (0LL + phiMp[j-1] + (phi[j * p] - phi[j * p - 1] + mod1) % mod1) % mod1;
        ll pq = p;
        int nows, lasts = 0;
        int sum = 0;
        int q;
        for(q=1; pq<=m; ++q, pq *= p){ // LCM : p^(q-1) 
            ll pa = 1;
            nows = 0;
            for(int a=0; a<q; a++, pa *= p){ // GCD : p^a
                int N = m / pa;
                int last = pq / pa;
                int now = 0;
                for(int l=1, r; l<=N; l=r+1){ // Last part GCD
                    r = N / (N / l);
                    int val1 = (N / l) - (N / l / last), val2 = (N / l / p) - (N / l / last);
                    now = (now + 1LL * pown[val1] * ((mod1 + phi[r] - phi[l-1]) % mod1)) % mod1;
                    now = (now + mod1 - 1LL * pown[val2] * ((mod1 + phi[r] - phi[l-1]) % mod1)) % mod1;
                    now = (now + mod1 - 1LL * pown[val1] * ((mod1 + phiMp[r / p] - phiMp[(l - 1) / p]) % mod1) % mod1) % mod1;
                    now = (now + 1LL * pown[val2] * ((mod1 + phiMp[r / p] - phiMp[(l - 1) / p]) % mod1) % mod1) % mod1;
                }
                nows = (nows + now * pa) % mod1;
            }
            sum = (sum + 1LL * (nows - lasts + mod1) % mod1 * (q - 1)) % mod1;
            lasts = nows;
        }
        sum = (sum + 1LL * (mod1 + compGCD - lasts) % mod1 * (q-1) % mod1) % mod1;
        res = (1LL * res * power<mod>(p, sum)) % mod;
    }
    printf("%d\n", res);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/RiverHamster/p/sol-oj4052.html