计蒜客 2019 ICPC中国南昌网络邀请赛 tsy’s number(莫比乌斯反演+数论分块+线性筛)

计蒜客 2019 ICPC中国南昌网络邀请赛 tsy’s number(莫比乌斯反演+数论分块+线性筛)

题目链接:https://nanti.jisuanke.com/t/38226
题目大意:给定T组正整数n,求 ∑ i = 1 n ∑ j = 1 n ∑ k = 1 n φ ( i ) φ ( j 2 ) φ ( k 3 ) φ ( i ) φ ( j ) φ ( k ) φ ( g c d ( i , j , k ) )   m o d   2 30 \sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}\sum\limits_{k=1}^{n}\frac{\varphi(i)\varphi(j^2)\varphi(k^3)}{\varphi(i)\varphi(j)\varphi(k)}\varphi(gcd(i,j,k))\space mod\space 2^{30} i=1nj=1nk=1nφ(i)φ(j)φ(k)φ(i)φ(j2)φ(k3)φ(gcd(i,j,k)) mod 230 的值。
题解:看着很唬人,其实还是有套路的。。。
原式: ∑ i = 1 n ∑ j = 1 n ∑ k = 1 n φ ( i ) φ ( j 2 ) φ ( k 3 ) φ ( i ) φ ( j ) φ ( k ) φ ( g c d ( i , j , k ) ) \sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}\sum\limits_{k=1}^{n}\frac{\varphi(i)\varphi(j^2)\varphi(k^3)}{\varphi(i)\varphi(j)\varphi(k)}\varphi(gcd(i,j,k)) i=1nj=1nk=1nφ(i)φ(j)φ(k)φ(i)φ(j2)φ(k3)φ(gcd(i,j,k))
= ∑ i = 1 n ∑ j = 1 n ∑ k = 1 n j k 2 φ ( g c d ( i , j , k ) ) =\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}\sum\limits_{k=1}^{n}jk^2\varphi(gcd(i,j,k)) =i=1nj=1nk=1njk2φ(gcd(i,j,k))
= ∑ i = 1 n ∑ j = 1 n ∑ k = 1 n j k 2 ∑ d = 1 n φ ( d ) [ g c d ( i , j , k ) = d ] =\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}\sum\limits_{k=1}^{n}jk^2\sum\limits_{d=1}^{n}\varphi(d)[gcd(i,j,k)=d] =i=1nj=1nk=1njk2d=1nφ(d)[gcd(i,j,k)=d]
= ∑ d = 1 n φ ( d ) d 3 ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ n d ⌋ ∑ k = 1 ⌊ n d ⌋ j k 2 [ g c d ( i , j , k ) = 1 ] =\sum\limits_{d=1}^{n}\varphi(d)d^3\sum\limits_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum\limits_{j=1}^{\lfloor\frac{n}{d}\rfloor}\sum\limits_{k=1}^{\lfloor\frac{n}{d}\rfloor}jk^2[gcd(i,j,k)=1] =d=1nφ(d)d3i=1dnj=1dnk=1dnjk2[gcd(i,j,k)=1]
= ∑ d = 1 n φ ( d ) d 3 ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ n d ⌋ ∑ k = 1 ⌊ n d ⌋ j k 2 ε ( g c d ( i , j , k ) ) =\sum\limits_{d=1}^{n}\varphi(d)d^3\sum\limits_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum\limits_{j=1}^{\lfloor\frac{n}{d}\rfloor}\sum\limits_{k=1}^{\lfloor\frac{n}{d}\rfloor}jk^2\varepsilon (gcd(i,j,k)) =d=1nφ(d)d3i=1dnj=1dnk=1dnjk2ε(gcd(i,j,k))
= ∑ d = 1 n φ ( d ) d 3 ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ n d ⌋ ∑ k = 1 ⌊ n d ⌋ j k 2 ∑ t ∣ i , t ∣ j , t ∣ k μ ( t ) =\sum\limits_{d=1}^{n}\varphi(d)d^3\sum\limits_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum\limits_{j=1}^{\lfloor\frac{n}{d}\rfloor}\sum\limits_{k=1}^{\lfloor\frac{n}{d}\rfloor}jk^2\sum\limits_{t\mid i,t\mid j,t\mid k}\mu(t) =d=1nφ(d)d3i=1dnj=1dnk=1dnjk2ti,tj,tkμ(t)
= ∑ d = 1 n φ ( d ) d 3 ∑ t = 1 ⌊ n d ⌋ μ ( t ) t 3 ∑ i = 1 ⌊ n d t ⌋ ∑ j = 1 ⌊ n d t ⌋ ∑ k = 1 ⌊ n d t ⌋ j k 2 =\sum\limits_{d=1}^{n}\varphi(d)d^3\sum\limits_{t=1}^{\lfloor\frac{n}{d}\rfloor}\mu(t)t^3\sum\limits_{i=1}^{\lfloor\frac{n}{dt}\rfloor}\sum\limits_{j=1}^{\lfloor\frac{n}{dt}\rfloor}\sum\limits_{k=1}^{\lfloor\frac{n}{dt}\rfloor}jk^2 =d=1nφ(d)d3t=1dnμ(t)t3i=1dtnj=1dtnk=1dtnjk2
f ( x ) = ∑ t = 1 x μ ( t ) t 3 ∑ i = 1 ⌊ x t ⌋ ∑ j = 1 ⌊ x t ⌋ ∑ k = 1 ⌊ x t ⌋ j k 2 f(x)=\sum\limits_{t=1}^{x}\mu(t)t^3\sum\limits_{i=1}^{\lfloor\frac{x}{t}\rfloor}\sum\limits_{j=1}^{\lfloor\frac{x}{t}\rfloor}\sum\limits_{k=1}^{\lfloor\frac{x}{t}\rfloor}jk^2 f(x)=t=1xμ(t)t3i=1txj=1txk=1txjk2 ,函数前半部分的 μ ( t ) t 3 \mu(t)t^3 μ(t)t3 可以利用前缀和数组求值,后半部分可以利用数论分块加速。那么可以令原式为函数 g ( x ) g(x) g(x) ,则有 g ( x ) = ∑ d = 1 x φ ( x ) x 3 f ( ⌊ x d ⌋ ) g(x)=\sum\limits_{d=1}^{x}\varphi(x)x^3f(\lfloor\frac{x}{d}\rfloor) g(x)=d=1xφ(x)x3f(dx) ,同样的,这个函数的前半部分可以通过前缀和求出,后半部分也可以利用数论分块加速。
下面是AC代码。

#include
#include
#include
#include
using namespace std;
#define debug(x) cerr<<#x<<":"<
#define debug2(x,y) cerr<<#x<<":"<
#define debug3(x,y,z) cerr<<#x<<":"<
typedef long long ll;
struct fastio{
     
    fastio(){
     
        ios::sync_with_stdio(0);
        cin.tie(0);
        cout.tie(0);
    }
}fio;
const int N=1e7+5;
const int M=1<<30;
const int INV3=1789569707;
vector<int> prime,part,mu,s1,s2,phi;
void init(){
     
    phi=s1=s2=part=vector<int>(N,0);
    mu=vector<int>(N,-1);
    s1[1]=s2[1]=phi[1]=mu[1]=1;
    for(ll i=2;i<N;++i){
     
        s2[i]=((((ll)mu[i]*i*i)%M*i)%M+M+(ll)s2[i-1])%M;
        if(!part[i]){
     
            prime.push_back(i);
            part[i]=i;
            phi[i]=i-1;
        }
        s1[i]=((((((ll)phi[i]*i)%M)*i)%M*i)%M+(ll)s1[i-1])%M;
        for(auto j:prime){
     
            if(i*j>=N) break;
            part[i*j]=j;
            if(i%j==0){
     
                mu[i*j]=0;
                phi[i*j]=((ll)j*(ll)phi[i])%M;
                break;
            }
            else{
     
                mu[i*j]=-mu[i];
                phi[i*j]=((ll)phi[i]*(ll)phi[j])%M;
            }
        }
    }
}
unordered_map<int,int> f_v;
ll f(ll x){
     
    if(f_v[x]) return f_v[x];
    ll res=0;
    for(ll l=1,r;l<=x;l=r+1){
     
        r=x/(x/l);
        ll y=((ll)(1+x/l)*(x/l)>>1ll)%M;
        res=(res+((s2[r]-s2[l-1])%M*((ll)(x/l)*y%M*y%M*(((ll)(x/l)<<1ll)+1)%M*INV3%M)+M)%M)%M;
    }
    return f_v[x]=res;
}
int g(ll x){
     
    int res=0;
    for(ll l=1,r;l<=x;l=r+1){
     
        r=x/(x/l);
        res=((res+(ll)(s1[r]-s1[l-1])%M*f(x/l)%M)%M+M)%M;
    }
    return res;
}
signed main(){
     
    int t,n;
    cin>>t;
    init();
    while(t--){
     
        cin>>n;
        cout<<g(n)<<endl;
    }
}

要注意的是,我们可以利用map对 f ( x ) f(x) f(x) 的值进行储存,避免不必要的计算(如果不用map会TLE的说)。同时结果要返回正整数值,否则会WA。

(勉勉强强卡过了吧。。。)

你可能感兴趣的:(数论,莫比乌斯反演,acm竞赛)