zoukankan      html  css  js  c++  java
  • 51NOD 1594:Gcd and Phi——题解

    http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1594

    参考及详细推导:http://www.cnblogs.com/rir1715/p/8584083.html

    (cnt_i=sum_{j=1}^n[phi(j)==i]),这个可以在(O(n))处理出来。

    我们用它把(phi(i)phi(j))换元得:

    (sum_{i=1}^nsum_{j=1}^nphi(gcd(i,j)) imes cnt_i imes cnt_j)

    (=sum_{d=1}^nphi(d)sum_{i=1}^nsum_{j=1}^n[gcd(i,j)==d] imes cnt_i imes cnt_j)

    好的最难的部分已经过去了,随着一阵套路,这个式子索然无味。

    (=sum_{d=1}^nphi(d)sum_{d'=1}^nmu(d')(sum_{i=1}^{frac{n}{dd^`}}cnt_{idd'})^2)

    (sum(t)=sum_{i=1}^{frac{n}{t}}cnt_{it}),这个可以在(O(nlogn))处理出来(调和级数)。

    式子

    (=sum_{d=1}^nphi(d)sum_{d'=1}^nmu(d')sum(dd')^2)

    然后我们发现当(dd'>n)(sum(dd')=0),所以我们(d')不需要枚举那么多,所以最终的式子为:

    (sum_{d=1}^nphi(d)sum_{d'=1}^{frac{n}{d}}mu(d')sum(dd')^2)

    这个式子可以在(O(nlogn))运算(调和级数)。

    #include<map>
    #include<cmath>
    #include<stack>
    #include<queue>
    #include<cstdio>
    #include<cctype>
    #include<vector>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int N=2e6+5;
    inline int read(){
        int X=0,w=0;char ch=0;
        while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
        while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
        return w?-X:X;
    }
    bool he[N];
    int su[N],tot;
    ll phi[N],mu[N],cnt[N],sum[N];
    void Euler(int n){
        phi[1]=mu[1]=1;
        for(int i=2;i<=n;i++){
    	if(!he[i]){
    	    su[++tot]=i;
    	    phi[i]=i-1;mu[i]=-1;
    	}
    	for(int j=1;j<=tot&&i*su[j]<=n;j++){
    	    int p=su[j];he[i*p]=1;
    	    if(i%p==0){
    		mu[i*p]=0;phi[i*p]=phi[i]*p;
    		break;
    	    }else{
    		mu[i*p]=mu[i]*mu[p];phi[i*p]=phi[i]*phi[p];
    	    }
    	}
        }
    }
    int main(){
        Euler(N-5);
        int t=read();
        while(t--){
    	memset(cnt,0,sizeof(cnt));
    	memset(sum,0,sizeof(sum));
    	int n=read();
    	for(int i=1;i<=n;i++)cnt[phi[i]]++;
    	for(int i=1;i<=n;i++)
    	    for(int j=1;j<=n/i;j++)
    		sum[i]+=cnt[i*j];
    	for(int i=1;i<=n;i++)sum[i]*=sum[i];
    	ll ans=0;
    	for(int i=1;i<=n;i++)
    	    for(int j=1;j<=n/i;j++)
    		ans+=phi[i]*mu[j]*sum[i*j];
    	printf("%lld
    ",ans);
        }
        return 0;
    }
    
    

    +++++++++++++++++++++++++++++++++++++++++++

    +本文作者:luyouqi233。               +

    +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/ +

    +++++++++++++++++++++++++++++++++++++++++++

  • 相关阅读:
    书单
    x&(x1)表达式的意义
    约瑟夫环,杀人游戏(静态循环链表实现)
    我的第一个动态规划程序(试图用递归求斐波拉契数)
    NYOJ 2题 括号配对问题
    为什么 C++不叫作++C? o(∩_∩)o
    文字常量区,字符串常量
    括号匹配(栈实现)
    Mybatis的逆向工程(generator)
    Mybatis学习一(介绍/举例/优化)
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/9158444.html
Copyright © 2011-2022 走看看