码迷,mamicode.com
首页 > 其他好文 > 详细

各种反演难题训练集合

时间:2020-07-03 21:52:51      阅读:87      评论:0      收藏:0      [点我收藏+]

标签:知识   情况   c++   根据   out   开始   一个   reg   不同   

1.loj[6181]某个套路求和题

题意:

从前有个 alpha1022,他在看某本奇妙的书的时候想到了这样一个函数:

技术图片

 

 

然后就有了这样一个问题:

 

技术图片

 

 

 解体思路:

 

 

 观察发现,$f(i)$的值只有3种:0,-1,1。所以我们可以枚举不同值的方案数来得到答案。

首先考虑最好想的情况:值为0。易证当仅当一个数i有平方因子时才会为0.

然后对于一个数n,考虑(-1)的指数。假设i的质因子个数为m。指数根据组合数知识可以得到:$\sum_{i=0}^{m}i\binom{m}{i}$

对于上面的式子,当i取值k和m-k的时候组合数的值相同,所以合并一下可以得到:$\frac{1}{2}\sum_{i=0}^{m}m\binom{m}{i}$

根据二项式定理可以得到:指数为$m2^{m-1}$。

分析发现只有m为1时,也就是说只有n为质数的时候$f(i)$值才是-1,其余情况都是1。

于是可以考虑算出无平方因子的数的个数,然后减去质数的贡献。

注意是质数的贡献而不是质数的个数的原因是我们一开始算全部答案的时候默认i为质数时答案为1,而实际上答案是-1,差为2,所以贡献是质数的个数*2。

至于质数的贡献显然与质数的个数有关,因此min25筛可以解决后半部分。

对于无平方因子的数的个数,根据莫比乌斯函数的定义,我们知道答案就是$\sum_{i=1}^{n}\mu ^2(i)$。

直接算复杂度不对,我们考虑狄利克雷卷积或者莫比乌斯反演。

设$g(x)$表示x的最大平方因子的值。

显然$\sum_{i=1}^{n}\mu ^2(i)=\sum_{i=1}^{n}[g(i)=1]$

由于狄利克雷卷积中$Id∗1=σ1$

所以$\sum_{i=1}^{n}[g(i)=1]=\sum_{i=1}^{n}\sum_{k|g(i)}\mu (k)$

$=\sum_{d=1}^{n}\mu (d)\sum_{k|g(i)}$

$=\sum_{d=1}^{n}\mu (d)\sum_{k^2|i}$

$=\sum_{d=1}^{n}\mu (d)\frac{n}{d^2}$

至于这个东西我们发现n大于$\sqrt n$的时候对答案不会有任何贡献,因此枚举范围最大到$\sqrt n$即可。

这道题我们就愉快的AC啦~。

#include <bits/stdc++.h>
#define inc(i,a,b) for(register int i=a;i<=b;i++)
using namespace std;
int miu[200010],vis[200010],prime[200010],num,sg[200010];
const int p=998244353;
void pre(int n){
    inc(i,1,n) miu[i]=1;
    inc(i,2,n){
        if(vis[i]) continue;
        miu[i]=-1;
        for(int j=2*i;j<=n;j+=i){
            vis[j]=i;
            if((j/i)%i==0) miu[j]=0;
            else miu[j]*=-1;
        }
    }
    inc(i,1,n) vis[i]=0;
    vis[1]=1;
    inc(i,1,n){
        if(vis[i]==0){
            prime[++num]=i;
            sg[num]=sg[num-1]+1;
        }
        for(register int j=1;j<=num&&prime[j]*i<=n;j++){
            vis[i*prime[j]]=1;
            if(i%prime[j]==0)break;
        }
    }
}
long long n,sqrtn;
long long ans=0,w[2000010],ind1[2000010],ind2[2000010],tot,g[2000010];
int main(){
    cin>>n;
    sqrtn=sqrt(n);
    pre(sqrtn);
    for(long long i=1;i<=sqrtn;i++)  ans=((ans+miu[i]*(n/(i*i))%p)+p)%p;
    
    for(long long i=1;i<=n;){
        long long j=n/(n/i);
        w[++tot]=n/i;
        g[tot]=w[tot]-1;
        if(n/i<=sqrtn) ind1[n/i]=tot;
        else ind2[n/(n/i)]=tot;
        i=j+1;
    }        
    inc(i,1,num){
        //cout<<i<<endl;
        inc(j,1,tot){
            if(1ll*prime[i]*prime[i]>w[j]) break;
            long long k=((w[j]/prime[i]<=sqrtn)?(ind1[w[j]/prime[i]]):(ind2[n/(w[j]/prime[i])]));
            g[j]-=g[k]-sg[i-1];
        }
    }
    //cout<<"ac";
    cout<<((ans-2*g[1])%p+p)%p<<endl;
}

 

各种反演难题训练集合

标签:知识   情况   c++   根据   out   开始   一个   reg   不同   

原文地址:https://www.cnblogs.com/kamimxr/p/13232356.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!