BC #68 / hdu 5608 function · 莫比乌斯反演+杜教筛

题解

数论劝退…真的对第一次学的我太不友好了…

请务必看一下大佬的博客

首先,看到 d n f ( d ) \sum_{d|n}f(d) 要能想到莫比乌斯反演,

在莫比乌斯反演里有这么一个定理:

如果 F(n) 和 f(n) 满足 F ( n ) = d n f ( d ) F(n)=\sum_{d|n}f(d)
那么 f ( n ) = d n μ ( d ) F ( n d ) f(n)=\sum_{d|n}μ(d)F(⌊\frac{n}{d}⌋)

f = F μ f=F*μ
其中 μ μ 是莫比乌斯函数,是个积性函数哦

是不是和题目中的 i = 1 n f ( i ) \sum^{n}_{i=1}f(i) 联系起来了?

顺便改写一下题目, F ( n ) = n 2 3 n + 2 F(n)=n^2-3n+2

我们知道杜教筛是用来求积性函数的前缀和的,
那就直接让 S ( n ) = i = 1 n f ( i ) S(n)=\sum^{n}_{i=1}f(i) 吧!

然后,我们套用杜教筛常用公式 g ( 1 ) S ( n ) = i = 1 n ( f g ) ( i ) d = 2 n g ( d ) S ( n d ) g(1)S(n)=\sum^{n}_{i=1}(f*g)(i)-\sum^{n}_{d=2}g(d)S(⌊\frac{n}{d}⌋)
这里的 g g 选用恒等函数 I ( n ) I(n) ,对就是那个值恒等于1的积性函数,

然后改写一下公式: I ( 1 ) S ( n ) = i = 1 n ( f I ) ( i ) d = 2 n I ( d ) S ( n d ) I(1)·S(n)=\sum^{n}_{i=1}(f*I)(i)-\sum^{n}_{d=2}I(d)·S(⌊\frac{n}{d}⌋)
注意区分一下 ·是数值上的乘法,*是卷积,之前就这里把自己绕晕了

还记得之前说的 f = F μ f=F*μ 吗?
再改一下, S ( n ) = i = 1 n ( F μ I ) ( i ) d = 2 n S ( n d ) S(n)=\sum^{n}_{i=1}(F*μ*I)(i)-\sum^{n}_{d=2}S(⌊\frac{n}{d}⌋)

学习大佬博客后知道 μ I = ϵ μ*I=ϵ ,那个表示单位的元函数
(也就是说 I I μ μ 的逆元)

最后式子变成, S ( n ) = i = 1 n F ( i ) d = 2 n I ( d ) S ( n d ) S(n)=\sum^{n}_{i=1}F(i)-\sum^{n}_{d=2}I(d)·S(⌊\frac{n}{d}⌋)

结合题目,
S ( n ) = i = 1 n ( i 2 3 i + 2 ) d = 2 n I ( d ) S ( n d ) S(n)=\sum^{n}_{i=1}(i^2-3i+2)-\sum^{n}_{d=2}I(d)·S(⌊\frac{n}{d}⌋)

其中 i = 1 n ( i 2 3 i + 2 ) = n ( n + 1 ) ( n + 2 ) 6 3 n ( n + 1 ) 2 + 2 n = n ( n 1 ) ( n 2 ) 3 \sum^{n}_{i=1}(i^2-3i+2)=\cfrac{n(n+1)(n+2)}{6}-3*\cfrac{n(n+1)}{2}+2n=\cfrac{n(n-1)(n-2)}{3}

最终,
S ( n ) = n ( n 1 ) ( n 2 ) 3 d = 2 n I ( d ) S ( n d ) S(n)=\frac{n(n-1)(n-2)}{3}-\sum^{n}_{d=2}I(d)·S(⌊\frac{n}{d}⌋)

我终于会了!!!


在这里插入图片描述


#include <bits/stdc++.h>
#include <tr1/unordered_map>//unordered_map所在的头文件
using namespace std;
typedef long long ll;
const int N=1e6+10;
const int mod=1e9+7;
int m;
unordered_map<int,ll>S;//n高达1e9 需要unordered_map存答案记忆化

ll inv3;
ll F(int n){return 1ll*n*n-1ll*3*n+2;}

ll qpow(ll a,ll b){
    ll res=1;
    while(b){
        if(b&1)res=res*a%mod;
        b>>=1;
        a=a*a%mod;
    }
    return res;
}

ll sum_f[N];
ll get_S(int n){
    if(n<=m) return sum_f[n];//如果n的范围小于根号(最大范围) 直接返回提前预处理好的前缀和
    if(S[n]) return S[n];//记忆化
    ll res=1ll*n*(n-1)%mod*(n-2)%mod*inv3%mod;//F前缀和
    for (int l = 2,r; l <=n ; l=r+1) {
        r=n/(n/l);
        res-=(r-l+1)*get_S(n/l)%mod;
            //I(d)在[l,r]的和
        res=(res+mod)%mod;//有负数的风险
    }
    return S[n]=res;
}

int n,k;
int mu[N],prime[N],tot=0;
bool vis[N];
void get_mu(){//筛选莫比乌斯函数
    mu[1]=1;
    for (int i = 2; i < N; ++i) {
        if(!vis[i]){
            prime[++tot]=i;
            mu[i]=-1;
        }
        for (int j = 1; j <= tot && i*prime[j]<N; ++j) {
            vis[i*prime[j]]=true;
            if(i%prime[j]==0){
                mu[i*prime[j]]=0;//里面肯定有两个prime[j]
                break;
            }else{
                mu[i*prime[j]]=-mu[i];//多了个质数
            }
        }
    }
}

void init(){
    m=(int)sqrt(1e9);//sqrt(1e9)
    inv3=qpow(3,mod-2);
    get_mu();
    for (int i = 1; i <= m; ++i) {//统计每个f[n] 就是反演那个推论
        for (int j = i; j <= m; j+=i) {
            sum_f[j]+=1ll*mu[i]*F(j/i);
            sum_f[j]%=mod;
        }
    }

    for (int i = 1; i <= m; ++i) {//小范围统计S[n]
        sum_f[i]=sum_f[i]+sum_f[i-1];
        sum_f[i]%=mod;
    }
}

int main(){
    ios::sync_with_stdio(0);
    init();//不预处理必T

    int T;
    cin>>T;
    for (int cs = 1; cs <= T; ++cs) {
        cin>>n;
        cout <<get_S(n) << endl;
    }
    return 0;
}
发布了34 篇原创文章 · 获赞 0 · 访问量 945

猜你喜欢

转载自blog.csdn.net/Yubing792289314/article/details/104229572
今日推荐