2017多校八 1002题 hdu 6134 Battlestation Operational 艾弗森约定 莫比乌斯函数 分块

博客详细介绍了如何使用艾弗森约定和莫比乌斯函数解决HDU 6134 Battlestation Operational问题。文章通过引用其他博主的文章来阐述思路,强调了预处理和分块技术在优化算法中的重要性。通过代码展示了解题过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接


题意:

Your should calculate the total damage to the battlefield. Formally, you should compute
f(n)=i=1nj=1iij[(i,j)=1],


where  [(i,j)=1]  evaluates to be  1  if  gcd(i,j)=1 , otherwise  0 .


思路:

先将艾弗森约定用莫比乌斯函数展开,如 [1] http://blog.youkuaiyun.com/wubaizhe/article/details/77338332 ——WuBaizhe

观察发现,需进行一些预处理,如 [2] http://blog.youkuaiyun.com/qq_30927651/article/details/77341086 ——风所在的街道


细节要点:

1. 对 [w - j + 1, w] 一整段增加 k 时,不需要一个个进行操作,而是可以 g[w - j + 1] += k, g[w + 1] -= k, 这样求一下前缀和,效果就相当于对一整段进行了操作。

2. 预处理出前缀和 sum 之后,可以运用 分块 的想法求和,[i, n / (n / i)] 的这段区间内 n / i 的值相同


Code:

#include <bits/stdc++.h>
#define maxn 1000000
typedef long long LL;
const LL mod = 1e9 + 7;
bool check[maxn + 10];
int mu[maxn + 10], prime[maxn + 10], n, maxq;
LL g[maxn + 10], sum[maxn + 10], u[maxn + 10];
inline int max(int a, int b) { return a > b ?a : b; }
inline int min(int a, int b) { return a < b ?a : b; }
void Mobius() {
    memset(check, 0, sizeof(check));
    mu[1] = 1;
    int tot = 0;
    for (int i = 2; i <= maxn; ++i) {
        if (!check[i]) {
            prime[tot++] = i;
            mu[i] = -1;
        }
        for (int j = 0; j < tot; ++j) {
            if (i * prime[j] > maxn) break;
            check[i * prime[j]] = true;
            if (i % prime[j] == 0) {
                mu[i * prime[j]] = 0;
                break;
            }
            else {
                mu[i * prime[j]] = -mu[i];
            }
        }
    }
}
void init() {
    for (int j = 1; j <= maxn; ++j) {
        g[j] += 1; g[j + 1] -= 1;
        int lim = ceil(1.0 * maxn / j);
        for (int k = 2; k <= lim; ++k) {
            int w = k * j;
            g[w - j + 1] += k, g[w-j+1] %= mod;
            if (w + 1 <= maxn) g[w + 1] = (g[w+1] + mod - k) % mod;
        }
    }
    for (int i = 1; i <= maxn; ++i) g[i] += g[i - 1], g[i] %= mod;
    for (int i = 1; i <= maxn; ++i) sum[i] = sum[i-1] + g[i], sum[i] %= mod;
    for (int i = 1; i <= maxn; ++i) u[i] = u[i-1] + mu[i];
}
void work() {
    LL ans = 0;
    int le, ri;
    for (int i = 1; i <= n; i = ri + 1) {
        le = i, ri = n / (n / i);
        ans = (ans + (u[ri] - u[le - 1] + mod) % mod * sum[n / i] % mod) % mod;
    }
    printf("%lld\n", ans);
}
int main() {
    Mobius(); init();
    while (scanf("%d", &n) != EOF) work();
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值