1. 程式人生 > >luogu3455 [POI2007]ZAP-Queries 簡單的莫比烏斯反演

luogu3455 [POI2007]ZAP-Queries 簡單的莫比烏斯反演

poi gcd www. swap sum () wap ace clas

link

ms是莫比烏斯反演裏最水的題。。。

題意:對於給定的整數a,b和d,有多少正整數對x,y,滿足x<=a,y<=b,並且gcd(x,y)=d。

多組詢問, T<=50000,d,a,b<=50000

稍微推下shizi

\(\sum_{i=1}^a\sum_{j=1}^b[\gcd(i,j)=d]\)

\(=\sum_{i=1}^{a/k}\sum_{j=1}^{b/k}[\gcd(i,j)=1]\)

\(=\sum_{i=1}^{a/k}\sum_{j=1}^{b/k}\sum_{d|i,d|j}\mu(d)\)

\(=\sum_{i=1}^{a/k}\sum_{j=1}^{b/k}\sum_{d|i,d|j}\mu(d)\)

\(=\sum_{d=1}^n\mu(d)\lfloor\frac a{kd}\rfloor\lfloor\frac b{kd}\rfloor\)

連枚舉倍數都不用。。。直接打個數論分塊就行了。。。復雜度\(O(T\sqrt n)\)

#include <cstdio>
#include <functional>
using namespace std;


bool visit[50010];
int prime[50010], mu[50010], tot, fuck = 50000;

int main()
{
    mu[1] = 1;
    for (int i = 2; i <= fuck; i++)
    {
        if (visit[i] == false) prime[++tot] = i, mu[i] = -1;
        for (int j = 1; j <= tot && i * prime[j] <= fuck; j++)
        {
            visit[i * prime[j]] = true;
            if (i % prime[j] == 0) break;
            mu[i * prime[j]] = -mu[i];
        }
        mu[i] += mu[i - 1];
    }
    int t;
    scanf("%d", &t);
    while (t --> 0)
    {
        int n, m, k;
        scanf("%d%d%d", &n, &m, &k);
        n /= k, m /= k;
        int res = 0;
        if (n > m) swap(n, m);
        for (int i = 1, j; i <= n; i = j + 1)
        {
            j = min(n / (n / i), m / (m / i));
            res += (mu[j] - mu[i - 1]) * (n / i) * (m / i);
        }
        printf("%d\n", res);
    }
    return 0;
}

40行一遍AC

於NOIWC2019 Day2晚試機

日推裏出現的題,竟然挺水

NOI Linux真TM難用,累死我了

luogu3455 [POI2007]ZAP-Queries 簡單的莫比烏斯反演