1. 程式人生 > >HDU 2588 數論 尤拉函式

HDU 2588 數論 尤拉函式

題目連結

題意很簡單,思路卻有點難想。

從已知條件一步步來分析:
GCDXN>=M1<=X<=N

可得出結論1,也是該題重要的突破口:
GCD(X,N)一定是N的約數

這個條件可以給我們一定啟發,因為 N 的約數一定是很有限的,我們可不可以列舉N的約數 P(隨便給的名字= =),且 P>=M呢?

假設我們已經得到了這樣一個P,這時問題轉化為:
<==> 求【1,N】中有多少個數X,滿足 GCDXN=P(P為一個已知的數)

想到這裡,解法其實離我們已經很近了。

列舉X的複雜度是 O(N),我們還有沒有更好的解法呢?
假設當前有一個滿足條件的X,讓我們來考慮他的性質


一.因為 GCD(X,N) = P的,所以 X/P 一定與 N/P 互質(結論很顯然)
二.因為 X<=N,故 X/P<=N/P一定成立

由這兩條性質 再結合尤拉函式的定義,很顯然:
求X的個數 <==> 求 不大於N/P且與其互質的 X/P的個數 即求ϕ(N/P)

聽說還有容斥的做法 但現在沒有一點思路,如果以後懂了再補上(佔坑
好像又亂立了一個flag
程式碼:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std; typedef long long ll; ll euler(ll x){ ll res = x; for(int i=2 ;i*i<=x ;i++){ if(x%i == 0){ res = res/i*(i-1); while(x%i==0) x/=i; } } if(x>1) res = res/x*(x-1); return res; } int main(){ int T; scanf("%d",&T); while
(T--){ ll n,m; scanf("%I64d%I64d",&n,&m); ll ans = 0; for(ll i=1 ;i*i<=n ;i++){ if(n%i == 0){ if(i >= m){ ans += euler(n/i); } if((n/i)>=m && n/i != i){ ans += euler(i); } } } printf("%I64d\n",ans); } return 0; }