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)=\begin{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)\)\((1\leq n,k \leq 10^{12})\)

题解

首先观察\(f(n)\),可以比较容易地推出\(f(n)=\phi(n)\)。推导过程如下:我们先假设一对\((x,y)\),使得\(x+y=n\)并且\(gcd(x,y)=k\neq1\),于是我们可以推出\(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('\n');}
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\n",res%Md);
}

int main() {
	read(n);read(k);
	Calc();
	return 0;
}
posted @ 2018-08-26 16:13  Apocrypha  阅读(288)  评论(0编辑  收藏  举报