1. 程式人生 > >hdu1695-GCD-莫比烏斯反演入門

hdu1695-GCD-莫比烏斯反演入門

這裡寫圖片描述
這裡F(X)為挑選數目為有多少對滿足 gcd(x,y)==e
並且 F(x)滿足第二張圖片
Fngcdnf(d)dngcdn123
不太懂這個就感覺比較神奇。然後就可以用第二張圖片來計算了。
注意有一個小trick,該答案中x和y相同的只能計算一次,於是計算一下x和y的min的範圍,在這個範圍內(x,y)和(y,x)都會計算一遍,所以我們直接減去就行。(當然存在更多的比較笨的計算方法啦!)
慢慢學習吧!
ps:用容斥什麼的可以慢慢寫?

#include <bits/stdc++.h>
typedef long long LL;
using namespace std;
/*   求莫比烏斯函式就是那個不知道有啥用的函式。
    那個函式有倆性質。()
    **************************
    根據莫比烏斯反演可以通過F(n)來計算f(n)
    或者通過 f(n)來計算F(n)。
    這兩個都是 算術函式(定義域為所有正整數的函式)

*/
const int MAXN = 100000;
/*//線性篩法求莫比烏斯函式
bool check[MAXN+10];
int prime[MAXN+10];
int mu[MAXN+10];
void Moblus()
{
    memset(check,false,sizeof(check));
    mu[1] = 1;
    int tot = 0;
    for(int i = 2; i <= MAXN; i++)
    {
        if( !check[i] )
        {
            prime[tot++] = i;
            mu[i] = -1;
        }
        for(int j = 0; j < tot; j++)
        {
            if(i * prime[j] > MAXN) break;
            check[i * prime[j]] = true;
            if( i % prime[j] == 0)
            {
                mu[i * prime[j]] = 0;
                break;
            }
            else
            {
                mu[i * prime[j]] = -mu[i];
            }
        }
    }
}
*/
int mu[MAXN+10]={0}; void getMu(){//n*logn for(int i=1; i<=MAXN; i++) { int target = i==1?1:0; int delta = target - mu[i]; mu[i]=delta; for(int j=i*2; j<=MAXN; j+=i) mu[j]+=delta; } } int main() { int t; int a,b,c,d,e; getMu(); int
tim=1; scanf("%d",&t); while(t--){ scanf("%d%d%d%d%d",&a,&b,&c,&d,&e); if(!e){ printf("Case %d: 0\n",tim++); continue; } b/=e; d/=e; long long ans=0; long long rel=0; if(b>d)swap(b,d); for(int i=1;i<=min(d,b);i++){ ans+=1ll*mu[i]*(d/i)*(b/i);//用F_x來推斷f_x rel+=1ll*mu[i]*(b/i)*(b/i); } printf("Case %d: %lld\n",tim++,ans-rel/2); } return 0; }