zoukankan      html  css  js  c++  java
  • BZOJ4804: 欧拉心算

    Time Limit: 15 Sec Memory Limit: 256 MB
    Submit: 434 Solved: 262
    [Submit][Status][Discuss]

    Description

    给出一个数字N

    Input

    第一行为一个正整数T,表示数据组数。
    接下来T行为询问,每行包含一个正整数N。
    T<=5000,N<=10^7

    Output

    按读入顺序输出答案。

    Sample Input

    1

    10

    Sample Output

    136

    HINT

    Source

    By FancyCoder

    题解

    [sum_{i=1}^n sum_{j=1}^n phi(gcd(i,j)) ]

    [=sum_{i=1}^n sum_{j=1}^n sum_{d=1}^n phi(d)[gcd(i,j) =d] ]

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

    [=sum_{d=1}^nphi(d)sum_{i=1}^{lfloor frac{n}{d} floor} sum_{j=1}^{lfloor frac{n}{d} floor}[gcd(i,j)=1] ]

    不难发现(sum_{i=1}^{lfloor frac{n}{d} floor} sum_{j=1}^{lfloor frac{n}{d} floor}[gcd(i,j)=1])其实就是两倍欧拉函数前缀和减去1(因为(1,1)和(1,1)重复)

    于是线性筛(phi),求前缀和即可

    好像(n,n)改成(n,m)也可做,不过线筛起来挺(我)麻(不)烦(会)

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #include <map>
    #include <cmath>
    inline long long  max(long long a, long long b){return a > b ? a : b;}
    inline long long  min(long long a, long long b){return a < b ? a : b;}
    inline void swap(long long &x, long long &y){long long  tmp = x;x = y;y = tmp;}
    inline void read(long long &x)
    {
        x = 0;char ch = getchar(), c = ch;
        while(ch < '0' || ch > '9') c = ch, ch = getchar();
        while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar();
        if(c == '-') x = -x;
    }
    const long long INF = 0x3f3f3f3f;
    const long long MAXN = 10000000;
    
    long long p[MAXN + 1], bp[MAXN + 1], tot, phi[MAXN + 1];
    void make_phi()
    {
    	phi[1] = 1;
    	for(long long i = 2;i <= MAXN;++ i)
    	{
    		if(!bp[i]) phi[i] = i - 1, p[++ tot] = i;
    		for(long long j = 1;j <= tot && i * p[j] <= MAXN;++ j)
    		{
    			bp[i * p[j]] = 1;
    			if(i % p[j] == 0)
    			{
    				phi[i * p[j]] = phi[i] * p[j];
    				break;
    			}
    			phi[i * p[j]] = phi[i] * (p[j] - 1);
    		}
    	}
    	for(long long i = 1;i <= MAXN;++ i) phi[i] += phi[i - 1]; 
    } 
    long long t, n;
    int main()
    {
    	make_phi();
    	read(t);
    	for(;t;--t)
    	{
    		read(n);
    		long long ans = 0, r;
    		for(long long d = 1;d <= n;++ d)
    		{
    			r = min(n/(n/d), n);
    			ans += (phi[r] - phi[d - 1]) * ((phi[n/d] << 1) - 1);
    			d = r;
    		}
    		printf("%lld
    ", ans);
    	}
     	return 0;
    }
    
  • 相关阅读:
    第 33课 C++中的字符串(下)
    第 33课 C++中的字符串(上)
    第32课 初探C++标准库
    第31课 完善的复数类
    第30课 操作符重载
    第29课 类中的函数重载
    C++和C的相互调用
    函数重载遇上函数指针
    函数重载分析
    第2课 算法的效率问题
  • 原文地址:https://www.cnblogs.com/huibixiaoxing/p/8623470.html
Copyright © 2011-2022 走看看