「BZOJ3561」DZY Loves Math VI

Description

给定正整数 n,m 。求

i=1nj=1mlcm(i,j)gcd(i,j)

Input

一行两个整数n,m。

Output

一个整数,为答案模 109+7 后的值。

Sample Input

5 4

Sample Output

424

HINT

数据规模:

1n,m5×105 ,共有 3 组数据。

题解

莫比乌斯反演,关键还是推式子的过程。

======i=1nj=1mlcm(i,j)gcd(i,j)i=1nj=1m(ijgcd(i,j))gcd(i,j)d=1min(n,m)i=1nj=1m[gcd(i,j)=d](ijd)dd=1min(n,m)i=1ndj=1md[gcd(i,j)=1](ijd)dd=1min(n,m)ddi=1ndj=1mdε(gcd(i,j))(ij)dd=1min(n,m)ddi=1ndj=1md(ij)ddi,djμ(d)d=1min(n,m)ddd=1min(nd,md)μ(d)d2di=1nddj=1mdd(ij)d

完成!
这个式子看似是四重循环,但是最后两个 可以通过维护前缀和 O(1) 的计算答案,前面两重循环看似 O(n2) ,但是事实上复杂度用调和级数可证明为 O(nlnn)

My Code

/**************************************************************
    Problem: 3561
    User: infinityedge
    Language: C++
    Result: Accepted
    Time:7924 ms
    Memory:18872 kb
****************************************************************/

#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <vector>
#include <map>
#include <complex>

#define inf 0x3f3f3f3f
#define eps 1e-9
#define MAXN 500000
using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;

ll p[MAXN + 5]; int cnt, vis[MAXN + 5];
ll miu[MAXN + 5];

ll linear_shaker(){
    vis[1] = 1; miu[1] = 1;
    for(int i = 2; i <= MAXN; i ++){
        if(!vis[i]){
            p[++cnt] = i;
            miu[i] = -1;
        }
        for(int j = 1; j <= cnt && i * p[j] <= MAXN; j ++){
            if(i % p[j] == 0){
                vis[i * p[j]] = 1;
                miu[i * p[j]] = 0;
                break;
            }
            vis[i * p[j]] = 1;
            miu[i * p[j]] = -miu[i];
        }
    }
}
inline ll qpow(ll a, ll b){
    ll ret = 1;
    for(; b; b >>= 1, a = a * a % mod){
        if(b & 1) ret = ret * a % mod;
    }
    return ret;
}

ll n, m;
ll a[500005], sum[500005];
ll ans = 0;
int main(){
    linear_shaker();
    scanf("%lld%lld", &n, &m);
    if(n > m) swap(n, m);
    for(int i = 1; i <= m; i ++) a[i] = 1;
    for(ll d = 1; d <= n; d ++){
        for(int i = 1; i <= m / d; i ++){
            a[i] = a[i] * i % mod;
            sum[i] = (sum[i - 1] + a[i]) % mod;
        }
        ll tmp = 0;
        for(ll c = 1; c <= n / d; c ++){
            tmp = (tmp + miu[c] * qpow(c, 2 * d) % mod * sum[n / d / c] % mod * sum[m / d / c] % mod) % mod;
        }
        ans = (ans + qpow(d, d) * tmp) % mod;
    }
    printf("%lld\n", ans);
    return 0;
}


猜你喜欢

转载自blog.csdn.net/infinity_edge/article/details/78915463