由题引出欧拉函数 洛谷P2158

https://www.luogu.com.cn/problem/P2158

题面:在这里插入图片描述
我 们 定 义 C 君 坐 标 ( 0 , 0 ) , 我 们 猜 测 能 否 看 到 后 面 的 人 可 能 会 与 斜 率 有 关 。 我们定义C君坐标(0,0),我们猜测能否看到后面的人可能会与斜率有关。 C(0,0)
如 果 点 ( i , j ) 可 以 被 看 到 , 那 么 连 接 它 ( 0 , 0 ) 的 直 线 之 间 没 有 点 , 如果点(i,j)可以被看到,那么连接它(0,0)的直线之间没有点, (i,j)(0,0)线 也 就 是 这 条 线 之 间 没 有 点 的 斜 率 等 于 它 , 也就是这条线之间没有点的斜率等于它, 线 也 就 是 j i 不 能 约 分 。 也 就 是 gcd ⁡ ( i , j ) = 1 。 也就是\dfrac{j}{i}不能约分。也就是\gcd(i,j) = 1。 ijgcd(i,j)=1
那 么 我 们 只 需 要 找 到 每 个 j , 有 多 少 i 满 足 gcd ⁡ ( i , j ) = 1 。 那么我们只需要找到每个j,有多少 i 满足\gcd(i,j)=1。 jigcd(i,j)=1
而 这 刚 好 就 是 欧 拉 函 数 。 而这刚好就是欧拉函数。
E u l e r 函 数 : φ ( n ) 表 示 在 1 ∼ n 范 围 内 有 多 少 个 数 x 满 足 gcd ⁡ ( n , x ) = 1 。 Euler函数:\varphi(n)表示在1\sim n范围内有多少个数x满足\gcd(n,x)= 1。 Eulerφ(n)1nxgcd(n,x)=1
显 然 , 如 果 n 为 质 数 , φ ( n ) = n − 1 。 显然,如果n为质数,\varphi(n)=n-1。 ,n,φ(n)=n1
如 果 n 不 是 质 数 … … 不 想 写 了 如果n不是质数……不想写了 n—_—||| 以 后 再 来 补 以后再来补
这 里 给 出 log ⁡ 求 欧 拉 函 数 的 方 法 : 这里给出\log 求欧拉函数的方法: log

int euler(int n) {
    int ans = n;
    for (int i = 2; i * i <= n; ++i) {
        if (n % i == 0) {
            ans = ans / i * (i - 1);
            while (n % i == 0)n /= i;
        }
    }
    if (n > 1)ans = ans / n * (n - 1);
    return ans;
}

那 么 这 道 题 的 代 码 就 是 : 那么这道题的代码就是:

#include<bits/stdc++.h>

using namespace std;
//    clock_t start, end;
//    start = clock();
//    end = clock();
//    cout << (double) (end - start) / CLOCKS_PER_SEC << endl;
//ios::sync_with_stdio(false);
#define  int long long
#define double long double
#define rep(i, x, y) for(int i=(x);i<=(y);++i)
#define dep(i, x, y) for(int i=(x);i>=(y);--i)
#define gcd(a, b) __gcd(a,b)
const long long mod = 1e9 + 7;
const int maxn = 1e5 + 10;

int lowbit(int x) { return x & -x; }

bool ispow(int n) { return (n & (n - 1)) == 0; }//O(1) 判断是否是 2^k(2的k次方)
//12200160415121876738


int euler(int n) {
    int ans = n;
    for (int i = 2; i * i <= n; ++i) {
        if (n % i == 0) {
            ans = ans / i * (i - 1);
            while (n % i == 0)n /= i;
        }
    }
    if (n > 1)ans = ans / n * (n - 1);
    return ans;
}
int f[maxn];
signed main(){
    //freopen("01.in","r",stdin);
    int n;
    cin>>n;
    if(n == 1){
        cout << 0 << endl;
        return 0;
    }
    int ans = 3;
    for(int i =2;i<n;i++){
        ans += euler(i) * 2;
    }
    cout<<ans<<endl;
   return 0;

}

线 性 筛 求 φ ( n ) : 线性筛求\varphi(n): 线φ(n):

#include<bits/stdc++.h>

using namespace std;
//    clock_t start, end;
//    start = clock();
//    end = clock();
//    cout << (double) (end - start) / CLOCKS_PER_SEC << endl;
//ios::sync_with_stdio(false);
#define  int long long
#define double long double
#define rep(i, x, y) for(int i=(x);i<=(y);++i)
#define dep(i, x, y) for(int i=(x);i>=(y);--i)
#define gcd(a, b) __gcd(a,b)
const long long mod = 1e9 + 7;
const int maxn = 1e5 + 10;

int lowbit(int x) { return x & -x; }

bool ispow(int n) { return (n & (n - 1)) == 0; }//O(1) 判断是否是 2^k(2的k次方)
//12200160415121876738

int vis[maxn],prim[maxn],ff[maxn],cnt,num[maxn];
void f(/*线性筛*/) {
    for (int i = 2; i <= 50000; i++) {
        if (!vis[i])
            prim[cnt++] = i, num[i] = 1, ff[i] = i - 1;
        for (int j = 0; j < cnt && i * prim[j] <= 50000; j++) {
            vis[prim[j] * i] = 1;
            num[prim[j] * i] = num[i] + 1;
            if (i % prim[j] == 0) {
                ff[i * prim[j]] = prim[j] * ff[i];
                break;
            }
            ff[prim[j] * i] = ff[i] * ff[prim[j]];
        }
    }
}
signed main(){
    //freopen("01.in","r",stdin);
    int n;
    cin>>n;
    f();
    if(n == 1){
        cout << 0 << endl;
        return 0;
    }
    int ans = 3;
    for(int i =2;i<n;i++){
        ans += ff[i]*2;
    }
    cout<<ans<<endl;
   return 0;

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值