羅区3327:除数と

羅区3327:除数と

質問の意味の説明:

  • セット\(D(X)\)\(X \)番号除数、所与\(N、M \)要件:
  • \(\ sum_ 1} ^ {N-I = \ sum_ 1} = {J ^ MD)の(IJ \)\(T \)データのセット。
  • データ範囲\(T、N-、M \のLeq 50000 \)

思考

  • \(D(IJ)= \ sum_ {X | I} \ sum_ {Y | J} [GCD(X、Y)= 1] \)
  • 私たちはあなたを尋ねます:
  • \(\ sum_ {i = 1} ^ N \ sum_ {J = 1} ^ M \ sum_ {xは| I} \ sum_ {Y | jは} [GCD(X、Y)= 1] \)
  • 列挙\(X、Y \)です。
  • \(\ sum_ {X = 1} ^ N \ sum_ {Y = 1} ^ M [GCD(X、Y)= 1] \ sum_ {iは1 =} ^ N \ sum_ {J = 1} ^ M [X | N \と\ Y | M] \)
  • \(\ sum_ {X = 1} ^ N \ sum_ {Y = 1} ^ M [GCD(X、Y)= 1] \ FRAC {n}は{X} \ FRAC {M} {Y} \)
  • ...変数にそれを変更します。
  • \(\ sum_ {I = 1} ^ N \ sum_ {J = 1} ^ M [GCD(I、J)= 1] \ FRAC {n}は{I} \ FRAC {M} {J} \)
  • スタート反転:
  • \(F(X)= \ sum_ ^ {I 1 =} N \ sum_ {J = 1} ^ M [GCD(I、J)= X] \ FRAC {n}は{I} \ FRAC {M} {J } \)
  • ルーチンによると、次のとおりです。
  • \(F(X)= \ sum_ {X | D} F(D)= \ sum_ {I = 1} ^ N \ sum_ {J = 1} ^ M \ FRAC {n}は{I} \ FRAC {M} {J} [X | GCD(I、J)] \)
  • 列挙\(IX、JX \)があり、
  • \(= \ sum_ {i = 1} ^ {\ FRAC {n}は{X}} \ sum_ {J = 1} ^ {\ FRAC {M} {X}} \ FRAC {N} {IX} \ FRAC { M} {JX} \)
  • それは無視することができるように\(GCD(i、j)は \) 、この条件を。
  • そこ反転式:
  • \(F(X)= \ sum_ {X | D} \ミュー(\ FRAC {D} {X})F(D)\)
  • 私が知っている(ANS = F(1)\)\
  • \(= \ sum_ {1つの| D} \ MU(D)F(D)\)
  • \(= \ sum_ {D = 1} ^ {分(N、M)} \ MU(D)\ sum_ {i = 1} ^ {N / D} \ FRAC {N} {ジ} \ sum_ {J = 1} ^ {M / D} \ FRAC {M} {DJ} \)
  • 実際にあなたはここで行うことができますが、小さな問題があり、それはすぐに計算する方法である(\ sum_ {iは1を=} ^ N- \ N-FRACを{} {I} \)\
  • それは割り切れるブロックで処理することができます。
#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef long long ll;
const int maxn = 5e4 + 10;
int T, n, m;

bool vis[maxn];
int primes[maxn], mu[maxn], cnt, sum[maxn];
ll s[maxn];
void get_mu(int n)
{
    mu[1] = 1;
    for(int i = 2; i <= n; i++)
    {
        if(!vis[i])
        {
            primes[++cnt] = i;
            mu[i] = -1;
        }
        for(int j = 1; primes[j] <= n/i; j++)
        {
            vis[primes[j]*i] = 1;
            if(i % primes[j] == 0) break;
            else mu[i*primes[j]] = -mu[i];
        }
    }
    for(int i = 1; i <= n; i++)
        sum[i] = sum[i-1] + mu[i];
    for(int i = 1; i <= n; i++)
    {
        ll res = 0;
        for(int l = 1, r; l <= i; l = r + 1)
        {
            r = i/(i/l);
            res += 1ll*(r-l+1)*1ll*(i/l);
        }
        s[i] = res;
    }
}

inline void solve(int n, int m)
{
    if(n > m) swap(n, m);
    ll ans = 0;
    for(int l = 1, r; l <= n; l = r+1)
    {
        r = min(n/(n/l), m/(m/l));
        ans += 1ll*(sum[r]-sum[l-1])*1ll*s[n/l]*1ll*s[m/l];
    }
    printf("%lld\n", ans);
}

signed main()
{
    get_mu(50000);
    scanf("%lld", &T);
    while(T--)
    {
        scanf("%lld%lld", &n, &m);
        solve(n, m);
    }
    return 0;
}

おすすめ

転載: www.cnblogs.com/zxytxdy/p/12173434.html