bzoj2705(洛谷P2303): [SDOI2012]Longge的问题 (欧拉函数)

题意

i=1ngcd(i,n) ∑ i = 1 n g c d ( i , n )


题解

这题…真的要写一下了…
其实吧,结果就是 i|niφ(ni) ∑ i | n i ∗ φ ( n i )
然后!怎么求 varphi v a r p h i
这里给出一个超级厉害的做法!线筛+杜教筛!

当然如果你信了的话呢,咱们握握手吧!

直接求复杂度就是 n n 呀..很..赞..的!


代码

//正解!
#include <cstdio>
#include <cmath>
#define ll long long
ll n,ans;
ll phi(ll x){
    ll t=x;
    for(ll i=2;i<=sqrt(n);i++){
        if(x%i==0){
            t=t/i*(i-1);
            while(x%i==0) x/=i;
        }
    }
    if(x>1) t=t/x*(x-1);
    return t;
}
int main(){
//  freopen("a.in","r",stdin);
    scanf("%lld",&n);
    for(int i=1;i<=sqrt(n);i++){
        if(n%i==0){
            ans+=(ll)i*phi(n/i);
            ll x=n/i;
            if(i!=x) ans+=(ll)x*phi(n/x);
        }
    }
    printf("%lld\n",ans);
    return 0;
}
//傻子版!
#include <cstdio>
#include <cstring>
#include <cmath>
#include <map>
#include <algorithm>
using namespace std;
#define ll long long
#define N 2000010
#define U unsigned int
ll ans=0,phi[N],s1[N];
int n,tot,notprime[N],prime[N];
inline void euler(){
    phi[1]=1;
    for(int i=2;i<=2000000;i++){
        if(!notprime[i]) prime[++tot]=i,phi[i]=i-1;;
        for(int j=1;j<=tot && prime[j]*i<=2000000;j++){
            notprime[prime[j]*i]=1;
            if(i%prime[j]==0){
                phi[prime[j]*i]=phi[i]*prime[j];
                break;
            }phi[prime[j]*i]=phi[i]*phi[prime[j]];
        }
    }
    for(int i=2;i<=2000000;i++) phi[i]+=phi[i-1];
}
map<int,ll>mp;
inline ll calc(int x){
    if(x<=2000000) return phi[x];
    if(mp[x]) return mp[x];
    ll res=(ll)x*(x+1)>>1;
    for(U i=2,last;i<=x;i=last+1){
        last=x/(x/i);
        res-=calc(x/i)*(last-i+1);
    }mp[x]=res;
    return res;
}
int main(){
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    scanf("%d",&n);
    euler();memset(s1,0,sizeof(s1));
    for(int i=1;i<=sqrt(n);i++){
        if(n%i==0) ans+=(calc(n/i)-calc(n/i-1))*i;
        int x=n/i;
        if(n%x==0 && x!=i) ans+=(calc(n/x)-calc(n/x-1))*x;
    }
    printf("%lld",ans);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值