解方程【狄利克雷卷积+莫比乌斯反演+积性函数】

题意

数列 (f(i)) 使得对任意的 (n) 都有:

[sum_{i|n}{f(i) imes sigma_p(frac{n}{i})}=sigma_q(n) ]

其中,(sigma_k(n)) 表示 (n) 的约数的 (k) 次方和。求出 (f_imod 998244353 (1leq i leq n)) 的异或和。

(1leq n,p,q leq 10^7,且不保证 pleq q)

题目链接:https://ac.nowcoder.com/acm/contest/7329/F

分析

观察等式的左边,可以发现很符合狄利克雷卷积的形式,即:((f*sigma_p)(n)=sigma_q(n))

同时,发现:(sigma_k=Id_k*I),可以得到:((f*Id_p)(n)=Id_k(n)),即:

[sum_{i|n}{f(i) imes frac{n^p}{i^p}}=n^q ]

化简得:

[sum_{i|n}{frac{f(i)}{i^p}}=n^{q-p} ]

(F(n)=n^{q-p},g(n)=frac{f(n)}{n^p}),可以发现 (F(n)) 得求解很容易,而 (g(n)) 得求解较难(这不是刚好满足莫比乌斯反演吗)。根据莫比乌斯反演的约数形式:

[F(n)=sum_{d|n}f(d)Longrightarrow f(n)=sum_{d|n}{mu(d) imes F(frac{n}{d})} ]

可得:

[g(n)=frac{f(n)}{n^q}=sum_{d|n}{frac{mu(d)}{d^{q-p}}} ]

显然,(g(n)) 是一个积性函数,可以用线性筛处理,关键是如何求出 (n) 为质数和 (i\% prime[j])(i*prime[j])(g) 的函数值。

  • (n) 为质数时,代入易得 (g(n)=1-frac{1}{n^{q-p}})

  • (i\% prime[j]==0) 时,有 (g(i*prime[j])=g(i))

  • (i\% prime[j] eq 0) 时,根据积性函数,有 (g(i*prime[j])=g(i)*g(prime[j]))

对于 (n^q) ,由于数据比较大,因此要尽量减少使用快速幂的次数。

代码

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N=1e7+7;
const int mod=998244353;
int n,p,q;
bool vis[N];
int prime[N],tol,f[N];
ll num[N];
ll power(ll a,ll b)
{
    ll res=1;
    a%=mod;
    while(b)
    {
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
int solve()
{
    int ans=0,tol=0;
    f[1]=1;
    num[1]=1;
    for(int i=2;i<=n;i++)
    {
        if(!vis[i])
        {
            prime[++tol]=i;
            if(q<=p) f[i]=(1-power(i,p-q)+mod)%mod;
            else f[i]=(1-power(i,1LL*(q-p)*(mod-2))+mod)%mod;
            num[i]=power(i,q);
        }
        for(int j=1;j<=tol&&i*prime[j]<=n;j++)
        {
            vis[i*prime[j]]=1;
            num[i*prime[j]]=num[i]*num[prime[j]]%mod;
            if(i%prime[j]==0)
            {
                f[i*prime[j]]=f[i];
                break;
            }
            else
                f[i*prime[j]]=1LL*f[i]*f[prime[j]]%mod;
        }
    }
    for(int i=1;i<=n;i++)
        ans^=(1LL*f[i]*num[i]%mod);
    return ans;
}
int main()
{
    scanf("%d%d%d",&n,&p,&q);
    printf("%d
",solve());
    return 0;
}
原文地址:https://www.cnblogs.com/1024-xzx/p/13759097.html