牛客 D 月月给华华出题(欧拉函数)

链接:https://ac.nowcoder.com/acm/contest/392/D

题目描述
因为月月是个信息学高手,所以她也给华华出了一题,让他求:
∑Ni=1igcd(i,N)∑i=1Nigcd(i,N)
但是因为这个式子实在太简单了,所以月月希望华华对N=1,2,…,n各回答一次。华华一脸懵逼,所以还是决定把这个问题丢给你。

输入描述:
一个正整数n。
输出描述:
输出n行,第i行表示N=i时的答案。
示例1

输入
复制

6
输出
复制

1
2
4
6
11
11
备注:
1≤n≤1061≤n≤106

解析

首先有一个公式,
与n互质而且小于n的所有数的和为phi[n]*n/2
数组phi为欧拉函数

对于每一个N
gcd(i,N)==t
我们要考虑t取值不同时的所有贡献
而t只能是N的因子,对于N的因子x0,x1,x2,x3…来说
如果t=x0,即gcd(i,N)=x0
可以转化为gcd(i/x0,N/x0)=1
也就是说与N/x0互质的数再乘上x0就是i(分子),但式子本身两边除了x0,所以不用再乘x0直接就是对于结果的贡献
这对N产生的贡献就是phi[N/x0]*(N/x0)/2

如果我们对于每个N都枚举t肯定会超时,但是反过来想的话,我们可以枚举所有的t(因子),这样就会缩减时间复杂度。

coding

#include <bits/stdc++.h>
#define ll long long
#define pb push_back
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,b,a) for(int i=b;i>=a;i--)
using namespace std;
const int N=1e6+10;
ll phi[N],vis[N],pri[N];
ll ans[N];
int main()
{
    //ios::sync_with_stdio(false);
    ll n;
    scanf("%lld",&n);
    phi[1]=1;
    for(int i=2;i<=n;i++){
        if(!vis[i]){
            pri[++pri[0]]=i;
            phi[i]=i-1;
        }
        for(int j=1;j<=pri[0]&&pri[j]*i<=n;j++){
            vis[i*pri[j]]=1;
            if(i%pri[j]==0){
                phi[i*pri[j]]=phi[i]*pri[j];
                break;
            }
            else {
                phi[i*pri[j]]=phi[i]*phi[pri[j]];
            }

        }
    }
    for(ll i=1;i<=n;i++){
        for(ll j=i;j<=n;j+=i){
            ans[j]+=phi[j/i]*(j/i)/2ll;
        }
    }
    for(int i=1;i<=n;i++){
        printf("%lld\n",ans[i]+1ll);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值