• 【JZOJ4919】【NOIP2017提高组模拟12.10】神炎皇


    题目描述

    神炎皇乌利亚很喜欢数对,他想找到神奇的数对。
    对于一个整数对(a,b),若满足a+b<=n且a+b是ab的因子,则成为神奇的数对。请问这样的数对共有多少呢?

    数据范围

    对于100%的数据n<=100000000000000。

    =w=

    引理一

    两个互质的数之差与这两个数互质。
    证明:
    证明依赖于欧几里得算法的gcd(a,b)=gcd(b,ab)
    1.设a>b,r=(a,b),则有r|a,r|b,表示成a=ar,b=br
    则有(b,ab)=(br,(ab)r),显然(b,ab)也有r这个公约数。

    2.设r=(a,b),则有r|a,r|b,表示成a=ar,b=br
    则有(a+b,a)=((a+b)r,ar),显然(a+b,a)也有r这个公约数。

    综合1,2,(a,b)的公约数也是(b,ab)的公约数,所以gcd(a,b)=gcd(b,ab)
    回到原命题,gcd(p,q)=1gcd(q,pq)=1

    引理二

    两个互质的数的和与积互质。
    证明:
    gcd(p,q)=1
    根据引理一,则有
    gcd(p+q,q)=gcd(q,p)=1,gcd(p+q,p)=gcd(p,q)=1
    也就是说(p+q)pq都互质,必然就和pq互质。

    正文

    (a,b)合法,那么存在(a+b)|ab
    d=gcd(a,b),并且ad=a,bd=b
    那么就有(a+b)d|abd2,即(a+b)|abd


    根据引理二,又ab互质,则(a+b)|d
    题设有a+b<=n,那么(a+b)d<=n


    (a+b)|dd至少为(a+b)
    (a+b)d<=n,那么(a+b)<=n


    不妨枚举i=(a+b),这样d就只能取n/i个了,每隔i个有一个d|i
    所以合法的d就有n/i2个。
    再来考虑符合(a+b)=i的个数,由引理一:
    如果存在一个gcd(c,i)=1,那么必然存在一个gcd(c,ic)=1
    于是乎,(a+b)=i的个数即为φ(i),可用线性筛法预处理。


    综上,ans=ni=2ni2φ(i)
    时间复杂度为O(n)

    代码

    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    #include<math.h>
    #include<algorithm>
    #define ll long long
    using namespace std;
    const char* fin="uria.in";
    const char* fout="uria.out";
    const int inf=0x7fffffff;
    const int maxn=10000007;
    ll n,i,j,k,nq;
    ll ans;
    ll p[maxn],phi[maxn];
    bool bz[maxn];
    int main(){
        freopen(fin,"r",stdin);
        freopen(fout,"w",stdout);
        scanf("%lld",&n);
        nq=(ll)sqrt(n);
        for (i=2;i<=nq;i++){
            if (bz[i]==false){
                phi[i]=i-1;
                p[++p[0]]=i;
                ans+=phi[i]*(n/i/i);
            }
            for (j=1;j<=p[0];j++){
                k=i*p[j];
                if (k>nq) break ;
                if (i%p[j]==0) phi[k]=phi[i]*p[j];
                else  phi[k]=phi[i]*(p[j]-1);
                bz[k]=true;
                ans+=phi[k]*(n/k/k);
                if (i%p[j]==0) break;
            }
        }
        printf("%lld
    ",ans);
        return 0;
    }

    =o=

    线性筛法求欧拉函数

    首先有通式,
    φ(p1k1p2k2...pnkn)=(p11)p1k11(p21)p2k21...(pn1)pnkn1
    显然用线筛通过简单转移可以得到。

    ~

    一开始我也考虑分析这个东西,
    (a,b)合法就有(a+b)|abd
    然后就不会了。
    并没有考虑到gcd(a+b,ab)=1这个性质。
    日后这种数论计数问题,先从合法的开始分析。
    如果涉及倍数关系,可以考虑排除一些不作贡献的干扰项。

  • 相关阅读:
    [CetOS7]ssh信任
    Qt 路径中常用字符“./”、“../”、“/”、“*”的含义
    C++ fgets函数
    时间函数QueryPerformanceFrequency
    C++snprintf的使用
    提高C/C++运行效率以及避免出现Bug的20种方法
    Git 基本使用方法
    Eigen 矩阵基本运算
    Qt 断言Q_ASSERT的使用
    Qt QChart使用指南
  • 原文地址:https://www.cnblogs.com/hiweibolu/p/6714817.html
Copyright © 2020-2023  润新知