ナショナルチームのクラッシュデジタル形式

溶液

シーク
\ [\ sum_ {i = 1
\} ^ {N} \ sum_ {J = 1} ^ {M} LCM(I、J)]を元の式と等価である
[\ sum_ {i = 1から\ } ^ {Nを} \ sum_ {J = 1}
^ {M} \ FRAC {IJ} {GCD(I、J)} \] 古いルーチン、そのよう\(GCD(I、J)= D \)列挙で、D(\ \)
\ [\ sum_ {D = 1} ^ {N-} \ sum_ {I = 1} ^ {N-} \ sum_ {Jが= 1} ^ {M} [GCD(I、J)= D] \時間\ FRAC {IJ} {D} \
]は間違いなく上昇\(D \)を、\ (D \)\(\ FRAC {IJ} { D}は\) 寄与
\ [\ sum_ {D = 1 } ^ {N}のD \時間\ sum_ {i = 1} ^ {\ FRAC {n}は{D}} \ sum_ {J = 1} ^ {\ FRAC {M} {D}} [GCD(I、J)= 1] \回ijを\]
脳通さない\([GCD(I、J )= 1] \) 交換する
\ [\ sum_ {D = 1 } ^ {N}のD \回\ sum_ {i = 1 } ^ {\ FRAC {n}は {D}} \ sum_ {J = 1} ^ {\ FRAC {M} {D}} \ sum_ {K | GCD(I、J)} \ミュー(K)倍IJ \ \]
ルーチン列挙\(K \)
\ [\ sum_ {D = 1} ^ {N}のD \時間\ sum_ {k = 1} ^ {\ FRAC {n}は{D}}ミュー(K)\回\ \ sum_ {i = 1} ^ { \ FRAC {n}は{D}} \ sum_ {J = 1} ^ {\ FRAC {M} {D}} [K | GCD(I、J)]倍\ IJ \]
继续
\ [\ sum_ {D = 1} ^ {N}のD \時間\ sum_ {k = 1} ^ {\ FRAC {N}回\ MU(K)\ {D}} \ sum_ {IK = 1} ^ {\ FRAC {n}は{D }} \ sum_ {JK = 1} ^ {\ FRAC {M} {D}}回\ \倍のK ^ 2 \] IJ

\ [= \ sum_ {D = 1} ^ {N}のD \時間\ sum_ {k = 1} ^ {\ FRAC {n}は{D}}ミュー(K)\回\ \ sum_ {i = 1} ^ {\ FRAC {N} {DK}} \ sum_ {J = 1} ^ {\ FRAC {M} {DK}} \ \回K ^ 2 \ IJ倍】

ホーミング
\ [= \ sum_ {D = 1} ^ {N}のD \時間\ sum_ {k = 1} ^ {\ FRAC {n}は{D}} \ミュー(K)K ^ 2 \回\ sum_ { I = 1} ^ {\ FRAC
{N} {DK}} \ sum_ {J = 1} ^ {\ FRAC {M} {DK}} \回ijを\] 演算の数の代わりにカラム
[= \ sum_ \ {D = 1} ^ {N}のD \時間\ sum_ {k = 1} ^ {\ FRAC {n}は{D}}ミュー(K)K ^ 2 \回\ FRAC {N \ FRAC {} {DK}(\ \ FRAC {N} {DK}
+ 1)} {2} \回\ FRAC {\ FRAC {M} {DK}(\ FRAC {M} {DK} + 1)} {2} \] 取捨選択(\を\ MU(K)K ^ 2 \) 次いで、ブロック上のブロックにコピー数の数。

程度の複雑\(O(n)は、\)

どこにでもフィルムに。

コード

#include <bits/stdc++.h>
using namespace std;
#define re register
#define F first
#define S second
typedef long long ll;
typedef pair<int, int> P;
const int N = 1e7 + 5, M = 1e7 + 5, mod = 20101009;
const int INF = 0x3f3f3f3f;
inline int read() {
    int X = 0,w = 0; char ch = 0;
    while(!isdigit(ch)) {w |= ch == '-';ch = getchar();}
    while(isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48),ch = getchar();
    return w ? -X : X;
}
int p[N], mu[N];
ll sum[N];
bool vis[N];
int n, m;
void init(){
    int cnt = 0, k = min(n, m); mu[1] = 1;
    for (int i = 2; i <= k; i++){
        if (!vis[i]) p[++cnt] = i, mu[i] = -1;
        for (int j = 1; j <= cnt && i * p[j] <= k; j++){
            vis[i * p[j]] = 1;
            if (i % p[j] == 0) {
                mu[i * p[j]] = 0; break;
            }
            mu[i * p[j]] = -mu[i];
        }
    }
    for (int i = 1; i <= N; i++) sum[i] = (sum[i - 1] + 1ll * i * i % mod * (mu[i] + mod) % mod) % mod;
}
ll get(int n, int m){
    return (1ll * n * (n + 1) / 2 % mod)  * (1ll * m * (m + 1) / 2 % mod) % mod;
}
ll solsum(int n, int m){
    ll ans = 0;
    for (int i = 1, j; i <= min(n, m); i = j + 1){
        j = min(n / (n / i), m / (m / i));
        ans = (ans + 1ll * (sum[j] - sum[i - 1] + mod) % mod * get(n / i, m / i) % mod) % mod;
    }
    return ans;
}
ll solve(int n, int m){
    ll ans = 0;
    for (int i = 1, j; i <= min(n, m); i = j + 1){
        j = min(n / (n / i), m / (m / i));
        ans = (ans + 1ll * (j - i + 1) * (i + j) / 2 % mod * solsum(n / i, m / i) % mod) % mod;
    }
    return ans;
}
int main(){
    n = read(), m = read();
    init();
    printf("%lld\n", solve(n, m));
    return 0;
}

おすすめ

転載: www.cnblogs.com/lyfoi/p/11443357.html