• BZOJ.3944.Sum(杜教筛)


    BZOJ
    洛谷

    这题杜教筛已经被Min_25吊打了。


    又写个模板题用了半晚上。。

    卡常写法

    还非常短。。

    [Update] 卡了半天常,可能还不如换unordered_map快=-=
    见:https://www.luogu.org/recordnew/show/18243951
    也可能是我以前代码太丑了=-=

    //35332 kb	7608 ms
    //跟Kelin dalao学一波卡常。怎么还是很慢QAQ 
    //phi[]要longlong!
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    typedef long long LL;
    const int N=2e6;
    
    int cnt,Max,P[N>>3];
    LL phi[N],mu[N],sum[20005][2];
    bool Not_p[N],vis[20005];
    
    void Make_Table()
    {
    	mu[1]=phi[1]=1;
    	for(int i=2; i<N; ++i)
    	{
    		if(!Not_p[i]) P[++cnt]=i, mu[i]=-1, phi[i]=i-1;
    		for(int j=1,x; j<=cnt&&(x=i*P[j])<N; ++j)
    		{
    			Not_p[x]=1;
    			if(i%P[j]) mu[x]=-mu[i], phi[x]=phi[i]*(P[j]-1);
    			else {mu[x]=0, phi[x]=phi[i]*P[j]; break;}
    		}
    	}
    	for(int i=2; i<N; ++i) mu[i]+=mu[i-1],phi[i]+=phi[i-1];
    }
    inline LL Get_phi(int n){
    	return n<N?phi[n]:sum[Max/n][0];
    }
    inline LL Get_mu(int n){
    	return n<N?mu[n]:sum[Max/n][1];
    }
    void Calc(int n)
    {
    	if(n<N) return;
    	if(vis[Max/n]) return;
    	int t=Max/n;
    	vis[t]=1, sum[t][0]=((LL)n+1)*n>>1, sum[t][1]=1;//n+1可能爆int!
    	for(LL nxt,i=2; i<=n; i=nxt+1){
    		nxt=n/(n/i), Calc(n/i);
    		sum[t][0]-=Get_phi(n/i)*(nxt-i+1), sum[t][1]-=Get_mu(n/i)*(nxt-i+1);
    	}
    }
    
    int main()
    {
    	Make_Table();
    	int T; scanf("%d",&T);
    	while(T--){
    		memset(vis,0,sizeof vis);
    		scanf("%d",&Max);
    		if(Max<N) printf("%lld %lld
    ",phi[Max],mu[Max]);//mu[]如果是int就不要用%lld。
    		else Calc(Max),printf("%lld %lld
    ",sum[1][0],sum[1][1]);
    	}
    	return 0;
    }
    

    朴素写法

    //
    //phi[]要longlong!
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    typedef long long LL;
    const int N=5e6;
    
    int cnt,Max,P[N>>3],mu[N];
    LL phi[N],sum[20005][2];
    bool Not_p[N],vis[20005][2];
    
    void Make_Table()
    {
    	mu[1]=phi[1]=1;
    	for(int i=2; i<N; ++i)
    	{
    		if(!Not_p[i]) P[++cnt]=i, mu[i]=-1, phi[i]=i-1;
    		for(int j=1; j<=cnt&&i*P[j]<N; ++j)
    		{
    			Not_p[i*P[j]]=1;
    			if(i%P[j]) mu[i*P[j]]=-mu[i], phi[i*P[j]]=phi[i]*(P[j]-1);
    			else {mu[i*P[j]]=0, phi[i*P[j]]=phi[i]*P[j]; break;}
    		}
    	}
    	for(int i=2; i<N; ++i) mu[i]+=mu[i-1],phi[i]+=phi[i-1];
    }
    LL Calc_p(LL n)//这的n为什么必须要开longlong(2147483647)?因为下边。。
    {
    	if(n<N) return phi[n];
    	if(vis[Max/n][0]) return sum[Max/n][0];
    	vis[Max/n][0]=1;
    	LL res=1ll*n*((LL)n+1)>>1;//n+1可能爆int!
    	for(LL nxt,i=2; i<=n; i=nxt+1)//nxt+1可能爆int
    		nxt=n/(n/i), res-=Calc_p(n/i)*(nxt-i+1);
    	return sum[Max/n][0]=res;
    }
    LL Calc_m(int n)
    {
    	if(n<N) return mu[n];
    	if(vis[Max/n][1]) return sum[Max/n][1];
    	vis[Max/n][1]=1;
    	LL res=1;
    	for(LL nxt,i=2; i<=n; i=nxt+1)
    		nxt=n/(n/i), res-=Calc_m(n/i)*(nxt-i+1);
    	return sum[Max/n][1]=res;
    }
    
    int main()
    {
    	Make_Table();
    	int T,n; scanf("%d",&T);
    	while(T--){
    		memset(vis,0,sizeof vis);
    		scanf("%d",&Max),printf("%lld %lld
    ",Calc_p(Max),Calc_m(Max));
    	}
    	return 0;
    }
    

    map

    洛谷上还行吧。。BZOJ成功T掉。

    //phi[]要longlong!
    #include <map>
    #include <cstdio>
    #include <algorithm>
    typedef long long LL;
    const int N=6e6;
    
    int cnt,P[N>>3],mu[N];
    LL phi[N];
    bool Not_p[N];
    std::map<int,LL> mp[2];
    std::map<int,LL>::iterator it;
    
    void Make_Table()
    {
    	mu[1]=phi[1]=1;
    	for(int i=2; i<N; ++i)
    	{
    		if(!Not_p[i]) P[++cnt]=i, mu[i]=-1, phi[i]=i-1;
    		for(int j=1; j<=cnt&&i*P[j]<N; ++j)
    		{
    			Not_p[i*P[j]]=1;
    			if(i%P[j]) mu[i*P[j]]=-mu[i], phi[i*P[j]]=phi[i]*(P[j]-1);
    			else {mu[i*P[j]]=0, phi[i*P[j]]=phi[i]*P[j]; break;}
    		}
    	}
    	for(int i=2; i<N; ++i) mu[i]+=mu[i-1],phi[i]+=phi[i-1];
    }
    LL Calc_p(LL n)//这的n为什么必须要开longlong(2147483647)?
    {
    	if(n<N) return phi[n];
    	if((it=mp[0].find(n))!=mp[0].end()) return it->second;
    	LL res=n*(n+1)>>1;
    //	if(n&1) res=(n+1)/2*n;
    //	else res=n/2*(n+1);
    	for(LL nxt,i=2; i<=n; i=nxt+1)//nxt+1可能爆int
    		nxt=n/(n/i), res-=Calc_p(n/i)*(nxt-i+1);
    	return mp[0][n]=res;
    }
    LL Calc_m(int n)
    {
    	if(n<N) return mu[n];
    	if((it=mp[1].find(n))!=mp[1].end()) return it->second;
    	LL res=1;
    	for(LL nxt,i=2; i<=n; i=nxt+1)
    		nxt=n/(n/i), res-=Calc_m(n/i)*(nxt-i+1);
    	return mp[1][n]=res;
    }
    
    int main()
    {
    	Make_Table();
    	int T,n; scanf("%d",&T);
    	while(T--)
    		scanf("%d",&n),printf("%lld %lld
    ",Calc_p(n),Calc_m(n));
    	return 0;
    }
    
  • 相关阅读:
    关于C++名字空间
    选择组合OR继承?
    编译器为C++ 空类自动生成的成员函数
    函数返回值为引用类型
    关于数据库存储过程分页DatagridView BindingNavigator 控件的详细实现
    ADO.NET 安全编码指南 来自MSDN
    ADO.NET中调用存储过程
    视图
    高效使用连接的模式
    GROUP BY, HAVING, COMPUTE, ORDER BY 语句
  • 原文地址:https://www.cnblogs.com/SovietPower/p/8710976.html
Copyright © 2020-2023  润新知