BZOJ 2005 能量采集(莫比乌斯反演)

题目链接:
BZOJ 2005 能量采集
题意:
一块n*m的土地,能量采集器位与(0, 0),如果一棵植物与能量采集器连接成的线段上有k棵植物,那么能量损失为2*k+1,如果没有植物能量损失为1.求总的能量损失。
分析:
f(d)gcd(x,y)=d(x[1,n],y[1,n](x,y)
ans=i=ni=1(2i1)f(i) 。求解 f(d) 可以利用莫比乌斯反演。 F(d)d | gcd(x,y)(x,y)
:F(n)=d|ngcd(x,y)f(n)=n|dμ(dn)F(d),
ans=i=ni=1(2i1)d=nd=1μ(d)nidnid,

#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <string>
#include <bitset>
using namespace std;
typedef long long ll;
const int MAX_N = 100010;

bitset<MAX_N> bs;
int prime_cnt;
int prime[MAX_N], mu[MAX_N];
ll sum[MAX_N];

void GetMu()
{
    mu[1] = 1;
    prime_cnt = 0;
    bs.set();
    for(int i = 2; i < MAX_N; ++i) {
        if(bs[i]) {
            prime[prime_cnt++] = i;
            mu[i] = -1;
        }
        for(int j = 0; j < prime_cnt & i * prime[j] < MAX_N; ++j) {
            bs[i * prime[j]] = 0;
            if(i % prime[j]) {
                mu[i * prime[j]] = -mu[i];
            }else {
                mu[i * prime[j]] = 0;
                break;
            }
        }
    }
    for(int i = 1; i < MAX_N; ++i ){
        sum[i] = sum[i - 1] + mu[i];
    }
}

ll solve(int n, int m)
{
    ll res = 0;
    int top = min(n, m), last;
    for(int i = 1; i <= top; i = last + 1) {
        last = min(n / (n / i), m / (m / i));
        res += (sum[last] - sum[i - 1]) * (n / i) * (m / i);
    }
    return res;
}

int main()
{
    GetMu();
    int n, m;
    while(~scanf("%d%d", &n, &m)){
        ll ans = 0;
        int top = min(n, m);
        for(int i = 1; i <= top; i++){
            ans += solve(n / i, m / i) * (2 * i - 1);
        }   
        printf("%lld\n", ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值