1. 程式人生 > 實用技巧 >[2020.12.07週一]賽氪A題

[2020.12.07週一]賽氪A題

賽氪

題解:根據歐幾里得輾轉相除,很容易想到\(gcd(i,n-i)=gcd(i,n)\)

\[\begin{align*} &當n>1,f(n)=\sum_{i=1}^{n-1}[gcd(i,n-i)==1]=\sum_{i=1}^{n-1}[gcd(i,n)==1]+[gcd(n,n)==0]=\sum_{i=1}^{n}[gcd(i,n)==1]=\varphi (n)\\ &\therefore f(n)=\varphi(n)\\ &g(n)=\sum_{d|n}f(\frac{n}{d})=\sum_{d|n}f(\frac{n}{d})·1(d)=\varphi*1=id,恆等函式\\ &\therefore g(n)=n\\ &綜上,這題只要作(k+1)/2次尤拉就好了;\\ &但這個k依然很大,但沒關係因為log次必然迭代到1,按照cy的說法是暴跳到1然後break;\\ &複雜度O(n\log n)\\ &下面來證明[思路by cy]:log次必然迭代到1(賽場上因為沒證出來,不敢衝)\\ &根據尤拉定理,n=p_1^{k_1}p_2^{k_2}\cdots p_n^{k_n}\\ &\varphi(奇數)=偶數\\ &\varphi(偶數)\le偶數/2\\ &\varphi(n)\le n-1\\ &因此,\varphi(\varphi(n))\le n/2 \end{align*} \]

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
long long  euler(long long  n)
{
    long long res=n,a=n;
    for(long long i=2;i*i<=a;i++){
        if(a%i==0){
            res=res/i*(i-1);//先進行除法是為了防止中間資料的溢位
            while(a%i==0) a/=i;
        }
    }
    if(a>1) res=res/a*(a-1);
    return res;//返回euler(n)
}
int main()
{
    int  T;ll n, k;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%lld%lld",&n,&k);
        k=(k+1)/2;
        for(int i=1;i<=k;i++){
            n=euler(n);
            if(n==1) break;
        }
        printf("%lld\n",n%mod);
    }
}