• codeforces 776E The Holmes Children


    codeforces 776E The Holmes Children

    题目传送门

    题意

    定义(f(n))为满足(x+y=n)并且(gcd(x,y)=1)的有序正整数对个数,定义(g(n)=sum_{d|n}f(frac{n}{d})),定义(F_k(n))如下:

    [ F_k(n)=egin{cases} f(g(n)) & k=1 \ g(F_{k-1}(n)) & k>1且k\%mod=0 \ f(F_{k-1}(n)) & k>1且k\%mod=1 end{cases}]

    给出(n)(k),求(F_k(n))((1leq n,k leq 10^{12}))

    题解

    首先观察(f(n)),可以比较容易地推出(f(n)=phi(n))。推导过程如下:我们先假设一对((x,y)),使得(x+y=n)并且(gcd(x,y)=k eq1),于是我们可以推出(gcd(x,n-x)=k)(k)(x)(n-x)的一个因数,所以(k)也是(n)的一个因数,那么(gcd(n,x)=k),所以我们可以得知所有不满足条件的正整数对((x,y))(x)都不是与(n)互质的,所以满足条件的就是和(n)互质的那些,那么这个就是求欧拉函数了。
    然后我们去看(g(n)),可以退出(g(n)=n),因为一个数所有因数的欧拉函数之和等于这个数本身。推导过程如下:假设(n=a*b),那么(phi(b))为所有与(b)(gcd)为1的数,那么这些数与(n)(gcd)(a),所以所有与(n)(gcd)(a)的数都会对(phi(b))作出1的贡献,而由于每个小于(n)的数都与(n)有一个(gcd),所以每个数一定都会作出1的贡献,最后答案就是(n)
    知道这两个结论之后,就可以将(F_k(n))变成(phi^{frac{k+1}{2}}(n)),即求(frac{k+1}{2})次的欧拉函数,而由于欧拉函数的值求到(log)次左右之后就会变成1,所以我们最多求(log)次欧拉函数,直到(n=1)的时候,就可以直接输出答案了,总的复杂度为(O(logn*sqrt{n}))

    Code

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    bool Finish_read;
    template<class T>inline void read(T &x){Finish_read=0;x=0;int f=1;char ch=getchar();while(!isdigit(ch)){if(ch=='-')f=-1;if(ch==EOF)return;ch=getchar();}while(isdigit(ch))x=x*10+ch-'0',ch=getchar();x*=f;Finish_read=1;}
    template<class T>inline void print(T x){if(x/10!=0)print(x/10);putchar(x%10+'0');}
    template<class T>inline void writeln(T x){if(x<0)putchar('-');x=abs(x);print(x);putchar('
    ');}
    template<class T>inline void write(T x){if(x<0)putchar('-');x=abs(x);print(x);}
    /*================Header Template==============*/
    #define PAUSE printf("Press Enter key to continue..."); fgetc(stdin);
    const ll Md=1e9+7;
    ll n,k;
    /*==================Define Area================*/
    ll Euler(ll x) {
        ll res=x;
        for(ll i=2ll;i*i<=x;i++) {
            if(x%i==0) {
                res=res-res/i;
                while(x%i==0) x/=i;
            }
        }
        if(x>1) res-=res/x;
        return res;
    }
    
    void Calc() {
    	ll c=(k+1)/2;
    	ll res=Euler(n);
    	c--;
    	while(c--) {
    		res=Euler(res);
    		if(res==1) break;
    	}
    	printf("%lld
    ",res%Md);
    }
    
    int main() {
    	read(n);read(k);
    	Calc();
    	return 0;
    }
    
    「我不敢下苦功琢磨自己,怕终于知道自己并非珠玉;然而心中既存着一丝希冀,便又不肯甘心与瓦砾为伍。」
  • 相关阅读:
    每日一道面试题-02
    JAVA获取对象的四种方式
    每日一道面试题-01
    MD5算法原理浅谈
    JAVA--时间格式转换
    数据库-union和union all
    Struts1和Struts2的区别
    Java定时器Timer
    webView调试
    webView和js交互规范
  • 原文地址:https://www.cnblogs.com/Apocrypha/p/9537691.html
Copyright © 2020-2023  润新知