題目給定n,m 意思為二維座標系上從( 0, 0 ) 到 ( n, m )範圍裡,任意( x, y ) 和(0 , 0 )連成一條直線,在這條直線上的點的數量,所帶來的能量損失,能量損失公式為 2 k + 1, 其中k為點的數量,並且k不包括(0, 0) (x, y)。
題目分析,根據歐幾里德擴展算法中,我們能夠知道( 0, 0) 到 (x, y) 的直線上的整數點,就是gcd(x, y), 由於x y 和 0 0 不在考慮裡,所以直線上的點需要減2。
為了公式好推一點,我們設n為較大那一個 m為小的。
公式:
現在的任務變成如何快速計算gcd(i, j) 。
我們考慮gcd 為k 的個數數量為
我們再考慮一個函數,他的定義如下
為什麼要考慮這樣一個 Fi 呢?因為他很好求。
因為大於 i 的座標的點,並且這些點是 i 的倍數 最多只有 n / i 這麼多個, 而對於 j 而言也是 只有m / j 個。那麼我們可以快速得出結論
然後我們可以推出
我們的循環是要從頭開始還是從尾開始呢?
是要從尾開始的,因為我們肯定在i > n/2, Fi = fi, 因為2i 大於n。
答案的公式為:
記住這裡的 i 是指gcd(x, y) = i,我們是枚舉gcd不是計算gcd哦
所以你會發現,當m < n,的時候 fi = 0
#include <iostream>
using namespace std;
int main(){
long long n, m, ans, f[100005];
cin >> n >> m;
if(n < m) swap(n, m);
for(int i = n; i >= 1; i--){
f[i] = n / i * m / i;
for(int j = i + i; j <= n; j += i){
f[i] -= f[j];
}
ans += (2 * i - 1) * f[i];
}
cout << ans;
return 0;
}
莫比烏斯反演我是不會,但看樣子是可以用的。
根據大佬所說,調和級數 時間複雜度 是 O(NlogN)