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

    看着身边的大佬们这么快就学了各种筛,很是紧张啊……
    接下来强行学习一下

    简介

    用途:(O(n^frac{2}{3}))求积性函数的前缀和。

    本质就是推式子。
    设有某个函数(f(i)),我们要求(sum_{i=1}^nf(i))
    根据具体情况建出辅助函数(g(i))。求狄利克雷卷积(h=g*f)
    (S(n)=sum_{i=1}^n f(i))
    开始推式子:

    [sum_{i=1}^n h(i)=sum_{i=1}^nsum_{d|i}g(d)f(frac{i}{d}) \ =sum_{d=1}^ng(d)sum_{i=1}^{lfloorfrac{n}{d} floor}f(i) \ =sum_{d=1}^ng(d)S(lfloorfrac{n}{d} floor)]

    将右边式子第一项拆出来:

    [=g(1)S(n)+sum_{d=2}^ng(d)S(lfloorfrac{n}{d} floor) ]

    移项得(g(1)S(n)=sum_{i=1}^n h(i)-sum_{d=2}^ng(d)S(lfloorfrac{n}{d} floor))
    这个就是杜教筛的套路式了。
    使用杜教筛的时候,注意(sum_{i=1}^n h(i))(g(i))要能够快速地求出来。
    用整除分块来搞,时间复杂度据说是(O(n^{frac{2}{3}}))

    于是,学会这个套路之后,问题主要就是如何选取(g)(以及(h))。


    实现

    洛谷P4213 【模板】杜教筛(Sum)
    注意实现的时候,最好把(n)比较小的(S(n))都预处理出来。
    否则哈希容易爆炸。

    using namespace std;
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <unordered_map>
    #define ll long long
    #define M 1000000
    int n;
    int p[M+10],np;
    bool inp[M+10];
    int phi[M+10],mu[M+10];
    ll sum1[M+10],sum2[M+10];
    unordered_map<int,ll> ans1,ans2;
    ll get1(int n){
    	if (n<=M)
    		return sum1[n];
    	auto p=ans1.find(n);
    	if (p!=ans1.end())
    		return p->second;
    	ll res=(ll)(n+1)*n>>1;
    	for (unsigned i=2,j=2;i<=n;i=j+1){
    		j=n/(n/i);
    		res-=(j-i+1)*get1(n/i);
    	}
    	return ans1[n]=res;
    }
    ll get2(int n){
    	if (n<=M)
    		return sum2[n];
    	auto p=ans2.find(n);
    	if (p!=ans2.end())
    		return p->second;
    	ll res=1;
    	for (unsigned i=2,j=2;i<=n;i=j+1){
    		j=n/(n/i);
    		res-=(j-i+1)*get2(n/i);
    	}
    	return ans2[n]=res;
    }
    int main(){
    	phi[1]=mu[1]=1;
    	for (int i=2;i<=M;++i){
    		if (!inp[i]){
    			p[++np]=i;
    			phi[i]=i-1;
    			mu[i]=-1;
    		}
    		for (int j=1;j<=np && i*p[j]<=M;++j){
    			inp[i*p[j]]=1;
    			if (i%p[j]==0){
    				phi[i*p[j]]=phi[i]*p[j];
    				mu[i*p[j]]=0;
    				break;
    			}
    			phi[i*p[j]]=phi[i]*(p[j]-1);
    			mu[i*p[j]]=-mu[i];
    		}
    	}
    	for (int i=1;i<=M;++i){
    		sum1[i]=sum1[i-1]+phi[i];
    		sum2[i]=sum2[i-1]+mu[i];
    	}
    	int T;
    	scanf("%d",&T);
    	while (T--){
    		scanf("%d",&n);
    		printf("%lld %lld
    ",get1(n),get2(n));
    	}
    	return 0;
    }
    

    参考资料
    杜教筛

  • 相关阅读:
    request和request.form和request.querystring的区别
    VS2010中如何创建一个WCF
    ASP.Net MVC 3.0 之 MVCContrib的使用
    C# 请假小时数的计算(完整代码)
    C#调用WebService
    .Net Framework 框架工作原理
    做程序员的感悟
    WCF入门简单教程(图文) VS2010版
    仿淘宝的浮动工具栏(兼容IE6和其他浏览器)
    (原创)LINQ To SQL简单入门
  • 原文地址:https://www.cnblogs.com/jz-597/p/12797292.html
Copyright © 2011-2022 走看看