zoukankan      html  css  js  c++  java
  • Min25 筛学习笔记

    Min25 筛学习笔记

    用途

    (Min25) 筛 可以在 (Oleft(frac{n^{frac{3}{4}}}{log n} ight)) 或者 (Thetaleft(n^{1 - epsilon} ight)) 的时间复杂度下解决一类积性函数 的前缀和问题。

    要求 (f(p)) 是一个关于 (p) 的项数较少的多项式或可以快速求值;(f(p^c)) 可以快速求值。

    实现

    如果答案是一个多项式,那么我们要把这个多项式的每一项都拿出来求一次答案,最后把答案累加。

    (s(n,k)) 表示 (1sim n) 中所有的质数和最小质因子大于 (pri[k]) 的所有合数的答案。

    最终我们要求的就是 (s(n,0))

    枚举最小质因子,(s(n,k)=f(i)(i is a prime & i>pri[k+1])+sum_{i=k+1}^{pri[i] imes pri[i] leq n}sum_{j=1}^{pri[i]^j leq n} f(pri[i]^j) (s(frac{n}{pri[i]^j},i)+j!=1))

    之所以要加上一个 (j!=1)是因为类似于 (pri[i]^j,j geq 2) 的贡献并不会被计算。

    对于后面的这个部分,我们直接递归求解即可,不用记忆化复杂度也是正确的,而且 (f(pri[i]^j)) 根据我们的要求是可以快速计算的。

    问题就在于前面的部分怎么求,可以用一下简单的容斥。

    (1 sim n) 中所有质数的答案减去小于等于 (pri[k]) 的答案。

    对于小于等于 (pri[k]) 的答案,因为合法的质数大小是小于等于 (sqrt{n}) 的,所以可以用线性筛预处理。

    (1 sim n) 中所有质数的答案可以用 (dp) 预处理。

    (g(n,k))(1 sim n) 中所有质数和最小质因子大于 (pri[k]) 的合数的答案。

    因为只要求出所有质数的答案,所以我们可以把这个函数看成一个完全积性函数。

    (g(n,0)) 的答案是一个自然数幂和的形式,指数较小的时候可以直接用一个前缀和的公式 (O(1)) 计算,指数较大的时候就要考虑用伯努利数。

    转移方程

    (g(n,k)=g(n,k-1)-f(pri[k])(g(frac{n}{pri[k]},k-1)-g(pri[k-1],k-1)))

    含义就是去掉最小质因子恰好为 (pri[k]) 的合数的贡献。

    因为小于等于 (pri[k-1]) 的质数和 (pri[k]) 相乘得到的合数最小质因子小于 (pri[k]) ,所以它的贡献不能被计算,所以我们要把它减去,减去的部分恰好就是我们用线性筛处理出的前缀和。

    同时因为是完全积性函数,所以我们不用去考虑后面的地方有没有把这个东西除尽。

    发现可以把第二维滚掉,同时有用的第一维只有 (frac{n}{k}) 的形式,也就是说我们可以把第一维的下标映射到两个数组中。

    (maxcnt)(leq sqrt{n}) 的质数的个数,我们要的只是 (g(n,maxcnt)) 的值,所以第一维和第二维总共的状态不会很多。

    直接递推即可,注意边界。

    最后的时候还要把 (f(1)) 的值加上,因为我们并没有统计到它。

    代码

    P5325 【模板】Min_25筛

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<iostream>
    #define rg register
    const int maxn=1e6+5,mod=1e9+7,inv2=500000004,inv6=166666668;
    inline int delmod(rg int now1,rg int now2){
    	return now1-=now2,now1<0?now1+mod:now1;
    }
    inline int addmod(rg int now1,rg int now2){
    	return now1+=now2,now1>=mod?now1-mod:now1;
    }
    inline int mulmod(rg long long now1,rg int now2){
    	return now1*=now2,now1>=mod?now1%mod:now1;
    }
    typedef long long ll;
    bool not_pri[maxn];
    int pri[maxn],sp1[maxn],sp2[maxn],g1[maxn],g2[maxn],tot,v1[maxn],v2[maxn],sqr;
    ll w[maxn];
    void pre(rg int mmax){
    	not_pri[0]=not_pri[1]=1;
    	for(rg int i=2;i<=mmax;i++){
    		if(!not_pri[i]){
    			pri[++pri[0]]=i;
    			sp1[pri[0]]=addmod(sp1[pri[0]-1],i);
    			sp2[pri[0]]=addmod(sp2[pri[0]-1],mulmod(i,i));
    		}
    		for(rg int j=1;j<=pri[0] && 1LL*i*pri[j]<=mmax;j++){
    			not_pri[i*pri[j]]=1;
    			if(i%pri[j]==0) break;
    		}
    	}
    }
    ll n;
    int solve(rg ll x,rg int y){
    	if(y && x<=pri[y]) return 0;
    	rg int now=x<=sqr?v1[x]:v2[n/x];
    	rg int ans=delmod(delmod(g2[now],g1[now]),delmod(sp2[y],sp1[y]));
    	for(rg int i=y+1;i<=pri[0] && 1LL*pri[i]*pri[i]<=x;i++){
    		rg ll np=pri[i];
    		for(rg int j=1;np<=x;j++,np*=pri[i]){
    			rg ll tmp=np%mod;
    			ans=addmod(ans,tmp*(tmp-1)%mod*addmod(solve(x/np,i),j!=1)%mod);
    		}
    	}
    	return ans;
    }
    int main(){
    	scanf("%lld",&n);
    	sqr=sqrt(n);
    	pre(sqr+100);
    	rg ll now;
    	for(rg ll l=1,r;l<=n;l=r+1){
    		r=(n/(n/l));
    		now=n/l;
    		w[++tot]=now;
    		if(now<=sqr) v1[now]=tot;
    		else v2[n/now]=tot;
    		now%=mod;
    		g1[tot]=delmod((now+1)*now%mod*inv2%mod,1);
    		g2[tot]=delmod((2*now+1)%mod*(now+1)%mod*now%mod*inv6%mod,1);
    	}
    	for(rg int i=1;1LL*pri[i]*pri[i]<=n;i++){
    		for(rg int j=1;j<=tot && 1LL*pri[i]*pri[i]<=w[j];j++){
    			rg ll now=w[j]/pri[i];
    			now=now<=sqr?v1[now]:v2[n/now];
    			g1[j]=delmod(g1[j],mulmod(pri[i],delmod(g1[now],sp1[i-1])));
    			g2[j]=delmod(g2[j],mulmod(1LL*pri[i]*pri[i]%mod,delmod(g2[now],sp2[i-1])));
    		}
    	}
    	printf("%d
    ",addmod(1,solve(n,0)));
    	return 0;
    }
    
  • 相关阅读:
    方法重载的小demo
    面向对象的小demo
    直接选择排序
    冒泡排序
    杨辉三角用java实现
    从键盘输入成绩,找出最高分,并输出学生成绩等级。成绩>=最高分-10,为A,成绩>=最高分-20,为B,成绩>=最高分-30,为C,其余等级为D
    井号的含义
    svg snap 笔记
    jQuery 插件格式 规范
    工作遇到问题
  • 原文地址:https://www.cnblogs.com/liuchanglc/p/14567298.html
Copyright © 2011-2022 走看看