HDU 1695 GCD(莫比乌斯反演)

版权声明:没人会转的( ̄▽ ̄) https://blog.csdn.net/j2_o2/article/details/84840861
题目链接
题意

给你5个整数a,b,c,d,k求 Σ i = 1 b Σ j = 1 d G C D ( i , j ) = = k \Sigma_{i=1}^b \Sigma_{j=1}^dGCD(i,j) == k
满足的数量

思路

看了几篇博客才勉强好像有点感觉,感觉是容斥原理的正负值,用μ表示预处理μ,然后根据一个简单地的函数反演回去
看的第一篇博客,这篇还有本题的讲解,去重虽然没说但应该好理解
看的第二篇博客
第三篇博客
入门到题目都比较完整的整合版

代码
#include <stdio.h>
#include <algorithm>
using namespace std;

#define ll long long

const ll N = 100000;
ll prm[N+5], miu[N+5], vis[N+5], pnum;

void init()
{
    miu[1] = 1, pnum = 0;
    for(ll i = 2; i <= N; ++i)
    {
        if(!vis[i]) prm[pnum++] = i, miu[i] = -1;
        for(ll j = 0; j < pnum && i*prm[j] <= N; ++j)
        {
            vis[i*prm[j]] = 1;
            if(i%prm[j] == 0) break;
            miu[i*prm[j]] = -miu[i];
        }
    }
}

int main()
{
    init();
    ll t, ca  = 1;
    for(scanf("%lld",&t); ca <= t; ++ca)
    {
        ll a, b, c, d, k;
        scanf("%lld%lld%lld%lld%lld",&a,&b,&c,&d,&k);
        if(k == 0) printf("Case %lld: %lld\n",ca,0);
        else
        {
            b /= k, d /= k;
            ll up = min(b,d);
            ll ans = 0, tmp = 0;
            for(ll i = 1; i <= up; ++i)
            {
                ans += miu[i]*(b/i)*(d/i);
                tmp += miu[i]*(up/i)*(up/i);
            }
            printf("Case %lld: %lld\n",ca,ans-tmp/2);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/j2_o2/article/details/84840861