1. 程式人生 > >bzoj2705 [SDOI2012]Longge的問題——因數

bzoj2705 [SDOI2012]Longge的問題——因數

div str 防止 blank mes i++ ret bzoj using

題目:https://www.lydsy.com/JudgeOnline/problem.php?id=2705

一開始自己想了半天...

有了點思路:遍歷 n 的因數 k,每個因數要預處理出 gcd 等於這個因數的數的個數 s[k];

預處理過程中還要去重:s[k] = (n-1) / k , s[k] -= s[2*k] + s[3*k] +......,&(*%$^&...

正要勇猛去寫的時候還是點開了TJ,然後被自己的愚蠢暴擊...

考慮 gcd ( n , m ) = k 的 m 的個數,發現 gcd ( n/k , m/k ) = 1,也就是 phi ( n/k )!!!

所以遍歷因數,求它們的歐拉函數;

但範圍太大了不能預處理,所以暴力每次求;

然而發現自己暴力也不會了,想了許多純純的暴力...

還是要用公式的啊... phi (x) = x * ∏ ( 1 - 1 / p[i] );

總之,就是一道關於歐拉函數的水題...

代碼如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
ll n,ans;
ll phi(ll x)
{
    ll ret=x;
    
for(int i=2;i*i<=x;i++) if(x%i==0) { ret=ret/i*(i-1);//防止溢出 while(x%i==0)x/=i; } if(x>1) ret=ret/x*(x-1); return ret; } int main() { scanf("%lld",&n); for(int i=1;i*i<=n;i++) if(n%i==0) { ans+=i*phi(n/i);
if(i*i<n) ans+=n/i*phi(i);//別算2遍 sqrt(n) } printf("%lld",ans); return 0; }

bzoj2705 [SDOI2012]Longge的問題——因數