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;
}
发布了464 篇原创文章 · 获赞 36 · 访问量 21万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览