【bzoj1101】[POI2007]Zap

(markdown下题面排版好像很丑。。还是贴链接吧

题目链接

很显然的莫比乌斯

很容易就能写出式子:

f ( d ) = n <= m i n ( a , b ) d | n     F ( n ) μ ( n d )
其中 F ( n ) = a n b n

但是这个式子显然不可优化。。那么考虑换一种形式

f ( d ) = D = 1 m i n ( a , b ) d F ( D d ) μ ( D )

然后考虑 F ( n ) 这个式子里有两个向下取整。。。联想一下因数个数就会知道可能会有大量连续的 D 使得 F ( D d ) 相等

这些相等的值显然可以一起算,可以把 F ( D d ) 从和式中取出来,然后后面的 μ 用一个前缀和维护起来快速计算

然后就做完了==

代码:

#include<cstdio>
#include<vector>
#include<queue>
#include<ctime>
#include<algorithm>
#include<cstdlib>
#include<stack>
#include<cstring>
#include<cmath>
using namespace std;

typedef long long LL;

const int INF = 2147483647;
const int maxn = 50010;

LL crz;
int a,b,d;
int p[maxn],tot,mu[maxn],sum[maxn];
bool mark[maxn];

inline LL getint()
{
    LL ret = 0,f = 1;
    char c = getchar();
    while (c < '0' || c > '9')
    {
        if (c == '-') f = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9')
        ret = ret * 10 + c - '0',c = getchar();
    return ret * f;
}

inline void init(int n)
{
    mu[1] = 1;
    for (int i = 2; i <= n; i++)
    {
        if (!mark[i]) p[++tot] = i , mu[i] = -1;
        for (int j = 1; j <= tot; j++)
        {
            if (i * p[j] > n) break;
            mark[p[j] * i] = 1;
            if (i % p[j]) mu[p[j] * i] = -mu[i];
            else
            {
                mu[p[j] * i] = 0;
                break;
            }
        }
    }
    for (int i = 1; i <= n; i++)
        sum[i] = sum[i - 1] + mu[i];
}

inline LL cal(int a,int b,int D)
{
    int c = min(a / d,b / d);
    int na = a / D,nb = b / D;
    LL ret = 0;
    for (int d = 1; d != c;)
    {
        int nex = min(na / (na / (d + 1)),nb / (nb / (d + 1)));
        ret += 1ll * (na / nex) * (nb / nex) * (sum[nex] - sum[d]);
        d = nex;
    }
    ret += 1ll * mu[1] * (na / 1) * (nb / 1);
    return ret;
}

int main()
{
    #ifdef AMC
        freopen("AMC1.txt","r",stdin);
    #endif
    int n = getint();
    init(50000);
    for (int i = 1; i <= n; i++)
    {
        a = getint(); b = getint(); d = getint();
        printf("%lld\n",cal(a,b,d));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/joky_2002/article/details/79382548