EOJ Monthly 2019.11 E 数学题

EOJ Monthly 2019.11 E 数学题

题目链接
在这里插入图片描述
这题和多校以及今年网络赛的某题非常相似,算是比较套路的了。
先推f:
f ( n , k ) = Σ x 1 = 1 n Σ x 2 = 1 n … Σ x k = 1 n [ g c d ( x 1 , x 2 , … , x k , n ) = 1 ] = Σ x 1 = 1 n Σ x 2 = 1 n … Σ x k = 1 n e ( g c d ( x 1 , x 2 , … , x k , n ) ) = Σ x 1 = 1 n Σ x 2 = 1 n … Σ x k = 1 n Σ d ∣ g c d ( x 1 , x 2 , … , x k , n ) μ ( d ) = Σ d ∣ n μ ( d ) Σ x 1 = 1 n d Σ x 2 = 1 n d … Σ x k = 1 n d 1 = Σ d ∣ n μ ( d ) ( n d ) k \begin{aligned} f(n,k)&=\Sigma_{x_{1}=1}^{n}\Sigma_{x_{2}=1}^{n}\dots\Sigma_{x_{k}=1}^{n}[gcd(x_{1},x_{2},\dots,x_{k},n)=1] \\&=\Sigma_{x_{1}=1}^{n}\Sigma_{x_{2}=1}^{n}\dots\Sigma_{x_{k}=1}^{n}e(gcd(x_{1},x_{2},\dots,x_{k},n))\\&=\Sigma_{x_{1}=1}^{n}\Sigma_{x_{2}=1}^{n}\dots\Sigma_{x_{k}=1 }^{n}\Sigma_{d|gcd(x_{1},x_{2},\dots,x_{k},n)}\mu(d)\\&=\Sigma_{d|n}\mu(d)\Sigma_{x_{1}=1}^{\frac{n}{d}}\Sigma_{x_{2}=1}^{\frac{n}{d}}\dots\Sigma_{x_{k}=1 }^{\frac{n}{d}}1\\&=\Sigma_{d|n}\mu(d)(\frac{n}{d})^{k} \end{aligned} f(n,k)=Σx1=1nΣx2=1nΣxk=1n[gcd(x1,x2,,xk,n)=1]=Σx1=1nΣx2=1nΣxk=1ne(gcd(x1,x2,,xk,n))=Σx1=1nΣx2=1nΣxk=1nΣdgcd(x1,x2,,xk,n)μ(d)=Σdnμ(d)Σx1=1dnΣx2=1dnΣxk=1dn1=Σdnμ(d)(dn)k
所以:
Σ i = 1 n f ( i , k ) = Σ i = 1 n Σ d ∣ n μ ( d ) ( n d ) k = Σ d = 1 n μ ( d ) Σ i = 1 ⌊ n / d ⌋ i k \begin{aligned} \Sigma_{i=1}^{n}f(i,k)&=\Sigma_{i=1}^{n}\Sigma_{d|n}\mu(d)(\frac{n}{d})^{k}\\&=\Sigma_{d=1}^{n}\mu(d)\Sigma_{i=1}^{\lfloor n/d \rfloor}i^{k} \end{aligned} Σi=1nf(i,k)=Σi=1nΣdnμ(d)(dn)k=Σd=1nμ(d)Σi=1n/dik
得到上式就好做了:后边的和式使用拉格朗日插值法计算前 n n n 个数的 k k k 次幂和,前边的和式使用 数论分块 以及 杜教筛 就可以完成这个式子的计算,复杂度大约为 O ( n 1 2 k ) O(n^{\frac{1}{2}}k) O(n21k)

有关杜教筛莫比乌斯函数前缀和:

S ( n ) = Σ i = 1 n μ ( i ) S(n) = \Sigma_{i=1}^{n}\mu(i) S(n)=Σi=1nμ(i)则有
1 = Σ i = 1 n e ( i ) = Σ i = 1 n Σ d ∣ i μ ( i d ) I ( d ) = Σ d = 1 n I ( d ) Σ i = 1 ⌊ n / d ⌋ μ ( i ) = Σ d = 1 n S ( ⌊ n / d ⌋ ) = S ( n ) + Σ d = 2 n S ( ⌊ n / d ⌋ ) \begin{aligned} 1&=\Sigma_{i=1}^{n}e(i)\\&= \Sigma_{i=1}^{n}\Sigma_{d|i}\mu(\frac{i}{d})I(d)\\&=\Sigma_{d=1}^{n}I(d)\Sigma_{i=1}^{\lfloor n/d \rfloor}\mu(i)\\&=\Sigma_{d=1}^{n}S(\lfloor n/d \rfloor)\\&=S(n)+\Sigma_{d=2}^{n}S(\lfloor n/d \rfloor) \end{aligned} 1=Σi=1ne(i)=Σi=1nΣdiμ(di)I(d)=Σd=1nI(d)Σi=1n/dμ(i)=Σd=1nS(n/d)=S(n)+Σd=2nS(n/d)
S ( n ) = 1 − Σ d = 2 n S ( ⌊ n / d ⌋ ) S(n)=1-\Sigma_{d=2}^{n}S(\lfloor n/d \rfloor) S(n)=1Σd=2nS(n/d)

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<unordered_map>
#include<map>
using namespace std;
typedef long long ll;
const ll mod=998244353;
const int N=1005;
const int M=2000005;
ll n,k,mu[M]={},res[N]={};
ll coef[N]={},pref[N]={},suff[N]={};
unordered_map<ll,ll> mp;
//map<ll,ll> mp;
inline ll pow_mod(ll a,ll b) {
    ll ret=1;
    while(b) {
        if(b&1) ret=ret*a%mod;
        b>>=1;
        a=a*a%mod;
    }
    return ret;
}
inline ll mod_inv(ll a) {
    return pow_mod(a,mod-2);
}
inline void init(ll n,ll k) {
    res[0]=0;
    for(int i=1;i<=k+1;++i) {
        res[i]=res[i-1]+pow_mod(i,k);
        res[i]%=mod;
    }
    // calc coef[0]
    coef[0]=1;
    for(int i=-1;i>=-k-1;--i) {
        coef[0]*=(i+mod);
        coef[0]%=mod;
    }
    coef[0]=mod_inv(coef[0]);
    for(int i=1;i<=k+1;++i) {
        coef[i]=coef[i-1]*mod_inv(i)%mod;
        coef[i]*=(-k-2+i+mod);
        coef[i]%=mod;
    }
}
inline ll calc(ll n,ll k) {
    ll ret=0,tmp=1;
    if(n<=k+1) return res[n];
    if(n>=mod) {
        for(int i=0;i<=k+1;++i) {
            tmp=1;
            for(int j=0;j<=k+1;++j) {
                if(i!=j) {
                    tmp*=(n-j+mod)%mod;
                    tmp%=mod;
                }
            }
            ret+=tmp*coef[i]%mod*res[i]%mod;
            ret%=mod;
        }
        return ret;
    }
    else {
        pref[0]=n;
        //cout<<n<<" "<<k<<endl;
        for(int i=1;i<=k+1;++i) {
            pref[i]=pref[i-1]*((n-i+mod)%mod)%mod;
          //  cout<<pref[i]<<endl;
        }
        suff[k+1]=(n-k-1+mod)%mod;
        for(int i=k;i>=0;--i) {
            suff[i]=suff[i+1]*((n-i+mod)%mod)%mod;
            //cout<<suff[i]<<endl;
        }
        for(int i=0;i<=k+1;++i) {
            //cout<<coef[i]<<" "<<res[i]<<endl;
            if(!i) {
                ret+=suff[1]*coef[0]%mod*res[0]%mod;
            }
            else if(i==k+1) {
                ret+=pref[k]*coef[k+1]%mod*res[k+1]%mod;
            }
            else {
                ret+=suff[i+1]*pref[i-1]%mod*coef[i]%mod*res[i]%mod;
            }
            ret%=mod;
            //cout<<ret<<endl;
        }
    }
    return ret;
}
bool isprime[M]={};
ll prime[M]={},tot=0;
inline void getMu() {
    isprime[0]=isprime[1]=1;
    mu[0]=0; mu[1]=1;
    for(int i=2;i<M;++i) {
        if(!isprime[i]) {
            prime[tot++]=i;
            mu[i]=-1;
        }
        for(int j=0;j<tot&&prime[j]*ll(i)<ll(M);++j) {
            isprime[prime[j]*i]=1;
            if(i%prime[j]==0) {
                mu[i*prime[j]]=0;
                break;
            }
            else {
                mu[i*prime[j]]=mu[i]*mu[prime[j]];
            }
        }
    }
    for(int i=1;i<M;++i) {
        mu[i]=(mu[i-1]+mu[i]+mod)%mod;
    }
}
inline ll getPre(ll n) {
    if(n<M) return mu[n];
    if(mp.find(n)!=mp.end()) {
        return mp[n];
    }
    ll r,ret=0;
    for(ll d=2;d<=n;++d) {
        r=n/(n/d);
        ret+=getPre(n/d)*(r-d+1)%mod;
        ret%=mod;
        d=r;
    }
    return mp[n]=(1-ret+mod)%mod;
}
inline ll check(ll n,ll k) {
    ll ret=0;
    for(int i=1;i<=n;++i) {
        ret+=pow_mod(i,k);
        ret%=mod;
    }
    return ret;
}
int main(void)
{
    getMu();
    scanf("%lld%lld",&n,&k);
    init(n,k);
    ll r=0,ans=0;
    for(ll d=1;d<=n;++d) {
        r=n/(n/d);
        ans+=(getPre(r)-getPre(d-1)+mod)%mod*calc(n/d,k)%mod;
        ans%=mod;
        d=r;
    }
    printf("%lld\n",ans);
    return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值