BZOJ 4407: 于神之怒加强版 积性函数线性筛+反演

https://www.lydsy.com/JudgeOnline/problem.php?id=4407

题意:很简单不说了。

做法:废话不多说我们开始开心的推公式吧

首先为了方便我把(i,j)表示gcd(i,j),x=min(n,m),首先我们可以得到:

ans=\sum_{i=1}^{n} \sum_{j=1}^{m}(i,j)^{k}

我们枚举gcd可以得到如下式子:

ans=\sum_{d=1}^{x}d^{k} \sum_{i=1}^{n}\sum_{i=1}^{m}[(i,j)=d]=\sum_{d=1}^{x}d^{k}\sum_{i=1}^{\left \lfloor \frac{n}{d} \right \rfloor} \sum_{j=1}^{\left \lfloor \frac{m}{d} \right \rfloor} [(i,j)=1]

我们发现后面的那部分可以直接套用莫比乌斯反演的结论:

ans=\sum_{d=1}^{x}d^{k}\sum_{i=1}^{\left \lfloor \frac{n}{d} \right \rfloor} \sum_{j=1}^{\left \lfloor \frac{m}{d} \right \rfloor} \sum_{t|(i,j)}\mu(t)

我们在枚举t可以得到如下式子:

ans=\sum_{d=1}^{x} d^{k} \sum_{t=1}^{\left \lfloor \frac{n}{d} \right \rfloor} \mu(t)*\left \lfloor \frac{n}{td} \right \rfloor*\left \lfloor \frac{m}{td} \right \rfloor

我们发现td不好处理,我们设S=td,枚举S(其实是套路):

ans=\sum_{S=1}^{x}\left \lfloor \frac{n}{S} \right \rfloor\left \lfloor \frac{m}{S} \right \rfloor \sum_{d|S} d^{k}\sum_{(t*d)=S} \mu(t)=\sum_{S=1}^{x}\left \lfloor \frac{n}{S} \right \rfloor\left \lfloor \frac{m}{S} \right \rfloor\sum_{d|S} d^{k}\mu(\frac{S}{d})

我们设H(S)=\sum_{d|S} d^{k}\mu(\frac{S}{d}),我们发现他是一个积性函数,因此我们可以使用线性筛

同时只要我们发现他的特殊情况的值,就可以使用线性筛了:

H(p)=p^{k}-1 (p\in prime)

H(p^{m+1})=H(p^{m})*p^{k}(p\in prime)

同时我们在前面一部分可以使用分块所以总的时间复杂度为O(n+T*\sqrt{n})

#include "bits/stdc++.h"

using namespace std;
const double eps = 1e-8;
#define reg register
#define lowbit(x) x&-x
#define pll pair<ll,ll>
#define pii pair<int,int>
#define fi first
#define se second
#define makp make_pair

int dcmp(double x) {
    if (fabs(x) < eps) return 0;
    return (x > 0) ? 1 : -1;
}

typedef long long ll;
typedef unsigned long long ull;
const ull hash1 = 201326611;
const ull hash2 = 50331653;
const ll N = 5000000 + 10;
const int M = 1000 + 10;
const int inf = 0x3f3f3f3f;
const ll mod = 1000000000 + 7;
int vis[N], pri[N], phi[N], cnt, mu[N], k;
ll h[N];

void addmod(ll &x) {
    if (x >= mod) x -= mod;
}

ll quick(ll a, ll n) {
    ll ans = 1;
    while (n) {
        if (n & 1) ans = ans * a % mod;
        n >>= 1;
        a = a * a % mod;
    }
    return ans;
}

void init() {
    vis[1] = h[1] = 1;
    cnt = 0;
    for (int i = 2; i < N; i++) {
        if (!vis[i]) {
            pri[++cnt] = i;
            h[i] = (quick(i, k) - 1 + mod) % mod;
        }
        for (int j = 1; j <= cnt && i * pri[j] < N; j++) {
            vis[i * pri[j]] = 1;
            if (i % pri[j] == 0) {
                h[i * pri[j]] = h[i] * quick(pri[j], k) % mod;
                break;
            }
            h[i * pri[j]] = h[i] * ((quick(pri[j], k) - 1 + mod) % mod) % mod;
        }
    }
    for (int i = 1; i < N; i++) h[i] += h[i - 1];
}

ll solve(int n, int m) {
    ll ans = 0;
    int mn = min(n, m);
    for (int l = 1, r; l <= mn; l = r + 1) {
        r = min(n / (n / l), m / (m / l));
        ans += 1LL * (n / l) * (m / l) % mod * (h[r] - h[l - 1]) % mod;
        ans %= mod;
    }
    return ans;
}

int main() {
    int T, n, m;
    scanf("%d%d", &T, &k);
    init();
    while (T--) {
        scanf("%d%d", &n, &m);
        printf("%lld\n", solve(n, m));
    }
    return 0;
}
发布了130 篇原创文章 · 获赞 80 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/KXL5180/article/details/97484620
今日推荐