hdu 1695 莫比乌斯反演入门题

来源:互联网 发布:windows模块更新程序 编辑:程序博客网 时间:2024/06/16 12:23

题意

给出b, d, k,求满足1 ≤ x ≤ b,1 ≤ y ≤ d,并且 gcd(x, y) = k 的数对 (x, y) 的对数。
((x, y) 和 (y, x) 算作一种)

思路

  • 等价求满足1 ≤ x ≤ b/k,1 ≤ y ≤ d/k,并且 gcd(x, y) = 1 的数对 (x, y) 的对数
  • 设 f(k) 为 gcd(x, y) = k 的数对(x, y) 的对数,要求f(1)
  • 设F(k) 为 k | gcd(x, y) 的数对(x, y) 的对数。
  • 根据莫比乌兹公式
    f(d)=d|eNμ(ed)F(e)

    f(1)=e=1Nμ(e)F(e)

    当然(x, y) 和 (y, x) 算作一种,还需要有去重操作。
#include<iostream>#include<algorithm>#include<cstring>using namespace std;typedef long long ll;const int maxn = 1e6 + 4;const int inf = 0x3f3f3f3f;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 a, b, c, d, k;ll F[maxn];int main(){    int T, kase = 1;    cin>>T;    Moblus();    while(T--){        cin>>a>>b>>c>>d>>k;        if(k == 0){            cout<<"Case "<<kase++<<": 0"<<endl;            continue;        }        b /= k;        d /= k;        int ed = min(b, d);        ll f1 = 0;        for(int i = 1; i <= ed; i++){            F[i] = (ll)(b / i) * (ll)(d / i);            f1 += F[i] * mu[i];            //去重操作            F[i]= (ll)(ed / i) * (ll)(ed / i - 1);            f1 -= F[i] * mu[i] / 2;        }        cout<<"Case "<<kase++<<": "<<f1<<endl;    }}
原创粉丝点击