GCD SUM

P2398 GCD SUM

 

解法1. 筛出来欧拉数后暴力搜 80分(实在卡不过去最后俩点了)

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
typedef long long LL;
int primes[N], cnt;
bool st[N];
int phi[N];
LL temp;
bool fuck[N];

inline void get_primes(int n) //phi数组
{
//    phi[1] = 1;
    for(int i = 2; i <= n; i++)
    {
        if(!st[i])
        {
            primes[cnt++] = i;
            phi[i] = i - 1;
        }
        
        for(int j = 0; primes[j] * i <= n; j++)
        {
            st[primes[j] * i] = true;
            
            if(i % primes[j] == 0)
            {
                phi[primes[j] * i] = phi[i] * primes[j];
                break;
            }
            phi[primes[j] * i] = phi[i] * (primes[j] - 1);
        }
    }
}

inline void dfs(int u, int v, int rem)
{
    if(u == 1 || v >= cnt) return;
    
    for(int i = v; i < cnt && primes[i] <= u / 2; i++) //问题就是 如果剩下个数咋办。
        if(u % primes[i] == 0 && !fuck[u % primes[i]]) dfs(u / primes[i], v, rem);
    
//    cout<<u<<endl;
    if(!fuck[u]) temp += phi[u] * (rem / u), fuck[u] = true;
}

signed main()
{
    //预处理出来了质数数组,然后质数试除 时间复杂度1e5 * ln1e5 互质数直接欧拉函数处理 如果该数为质数便直接不用了
    int n;
    cin>>n;
    get_primes(n);
    LL ans = 0;//1LL * n * (n + 1) / 2; 
    for(register int i = 1; i <= n; i++) //ans加上每个数的互质个数(因为gcd互质数=1) 然后加上每个数的约数之和)
    {
        if(!st[i])
        {
            temp += phi[i];
            continue;
        }
        memset(fuck, false, sizeof fuck);
        dfs(i, 0, i);    
    }
    ans += 2 * temp;
    ans += 1LL * n * (n + 1) / 2;
    
    cout<<ans<<endl;
}

解法2: 筛出来欧拉函数后发现每个欧拉数被用了sum(1 ~ n/i)次 直接遍历1 ~ n 复杂度O(n) 100分  ''' 解法3:筛出数后数论分块 时间复杂度O(q√n) q是查询次数 代码等学会了后补TAT

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
typedef long long LL;
int primes[N], cnt;
bool st[N];
int phi[N];
LL temp;
bool fuck[N];

inline void get_primes(int n) //phi数组
{
//	phi[1] = 1;
	for(int i = 2; i <= n; i++)
	{
		if(!st[i])
		{
			primes[cnt++] = i;
			phi[i] = i - 1;
		}
		
		for(int j = 0; primes[j] * i <= n; j++)
		{
			st[primes[j] * i] = true;
			
			if(i % primes[j] == 0)
			{
				phi[primes[j] * i] = phi[i] * primes[j];
				break;
			}
			phi[primes[j] * i] = phi[i] * (primes[j] - 1);
		}
	}
}

signed main()
{
	//预处理出来了质数数组,然后质数试除 时间复杂度1e5 * ln1e5 互质数直接欧拉函数处理 如果该数为质数便直接不用了
	int n;
	cin>>n;
	get_primes(n);
	LL ans = 0;//1LL * n * (n + 1) / 2; 
	for(register int i = 1; i <= n; i++) //ans加上每个数的互质个数(因为gcd互质数=1) 然后加上每个数的约数之和)
	{
		int r = n / i;
		temp += 1LL * phi[i] * r * (r + 1) / 2;
	}
	ans += 2 * temp;
	ans += 1LL * n * (n + 1) / 2;
	
	cout<<ans<<endl;
}




posted @ 2022-04-30 15:02  lviy_ptilopsis^^  阅读(61)  评论(0)    收藏  举报