zoukankan      html  css  js  c++  java
  • [BZOJ 3944]sum(杜教筛)

    [BZOJ 3944]sum(杜教筛)

    题面

    (mu)(varphi)的前缀和

    分析

    套路公式:

    我们要求(f)的前缀和,构造两个函数(g,h)满足(h=f*g), (F,G,H)为它们的前缀和

    [g(1)F(n)=H(n)-sum_{d=2}^n g(d) F(frac{n}{d}) ]

    如果(f=mu),注意到(mu*I=varepsilon),那么(g(n)=I(n)=1,h(n)=varepsilon(n),H(n)=varepsilon(1)=1)

    代入得(F(n)=1-sum_{d=2}^n F(frac{n}{d}))

    如果(f=varphi),注意到(varphi * I=id),那么(g(n)=I(n)=1,h(n)=n,H(n)=sum_{i=1}^ni=frac{n(n+1)}{2})

    代入得(F(n)=frac{n(n+1)}{2}-sum_{d=2}^n F(frac{n}{d}))

    然后记忆化搜索,用map记录答案,求和的部分用数论分块

    注意两个前缀和最好一起筛,要不会TLE

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<map>
    #define maxn 2000000
    using namespace std;
    typedef long long ll;
    int cnt;
    bool vis[maxn+5];
    int prime[maxn+5];
    int phi[maxn+5];
    int mu[maxn+5];
    ll sum_phi[maxn+5]; 
    ll sum_mu[maxn+5];
    void sieve(int n){
    	phi[1]=mu[1]=1;
    	for(int i=2;i<=n;i++){
    		if(!vis[i]){
    			mu[i]=-1;
    			phi[i]=i-1;
    			prime[++cnt]=i; 
    		}
    		for(int j=1;j<=cnt&&i*prime[j]<=n;j++){
    			vis[i*prime[j]]=1;
    			if(i%prime[j]==0){
    				mu[i*prime[j]]=0;
    				phi[i*prime[j]]=phi[i]*prime[j];
    				break;
    			}else{
    				mu[i*prime[j]]=-mu[i];
    				phi[i*prime[j]]=phi[i]*phi[prime[j]]; 
    			}
    		}
    	}
    	for(int i=1;i<=n;i++) sum_mu[i]=sum_mu[i-1]+mu[i];
    	for(int i=1;i<=n;i++) sum_phi[i]=sum_phi[i-1]+phi[i]; 
    }
    
    int t;
    ll n; 
    map<ll,ll>ans_mu;
    map<ll,ll>ans_phi;
    struct node{
    	ll phi;
    	ll mu;
    	node(){
    		
    	}
    	node(ll _phi,ll _mu){
    		phi=_phi;
    		mu=_mu;
    	}
    };
    node dujiao_sieve(ll n){
    	if(n<=maxn) return node(sum_phi[n],sum_mu[n]);
    	if(ans_phi.count(n)) return node(ans_phi[n],ans_mu[n]);
    	ll ans1=n*(n+1)/2,ans2=1;
    	node tmp;
    	for(ll l=2,r;l<=n;l=r+1){
    		r=n/(n/l);
    		tmp=dujiao_sieve(n/l);
    		ans1-=(r-l+1)*tmp.phi;
    		ans2-=(r-l+1)*tmp.mu; 
    	} 
    	ans_phi[n]=ans1;
    	ans_mu[n]=ans2;
    	return node(ans1,ans2);
    }
    int main(){
    	sieve(maxn+5);
    	scanf("%d",&t);
    	while(t--){
    		scanf("%lld",&n);
    		node ans=dujiao_sieve(n);
    		printf("%lld %lld
    ",ans.phi,ans.mu);
    	}
    }
    
  • 相关阅读:
    opencv学习(六)——图像基本操作
    GAN实战笔记——第一章GAN简介
    opencv学习(三)——绘图功能
    opencv学习(四)——鼠标作为画笔
    TensorFlow从入门到入坑(1)
    opencv学习(五)——轨迹栏作为调色板
    GAN实战笔记——第二章自编码器生成模型入门
    TensorFlow从入门到入坑(2)
    KDE Plasma 卡住
    未来5到10年前端技术发展趋势分析
  • 原文地址:https://www.cnblogs.com/birchtree/p/11436982.html
Copyright © 2011-2022 走看看