羅バレーP3312 [SDOI2014] +番号テーブルメビウス反転セグメントツリーと約+の数をメッシュ


羅バレーP3327 [SDOI2015]と約数の数
****
###タブ

  • メビウス反転
  • ブロック割り切れます
  • リニアふるい
    ****
    ###序文
  • ブロックは、他の一般的な形割り切れるです。私は...突然実現した後、長い時間を分割する方法を見つけ出すのに長い時間をしました
    ****
    質問の###簡潔な意味
  • $ Dは、(X)$は、$ Xの$除数の数を表します。求めて、m個の$、$ Nを考える
    $$ \ sum_。1} ^ {N-I = \ sum_ ^ {J}。1枚のMD =(I J)$$
    ***
    ###アイデアを
  • まず、そのような一般的に使用される式を知っている必要があり:
    | \ sum_ {Y | J} $$ D(私はJを*)= \ sum_ {I X} [GCD(X、Y)== 1] $$

    以下のように、この式を覚えておいてください

  • :我々は$この式を使用$ D(i、j)を計算し、式は、元の取得に等しい
    1 $$ \ sum_ 1} ^ {N-I = \ sum_} = {J ^ MD(のIJ)= \ {I = sum_。 1} ^ n個の\ sum_ {J = 1} ^ m個の\ sum_ {X | I} \ sum_ {Y | J} [GCD(X、Y)== 1] $$
  • $ xは、Yは、$ I、Jの$因子、計算の複雑さは、我々は、$ X、Y $は、$ N-明らかで、最大数mについて、それぞれ、超えていない$ $ N、Mを過度に激しい列挙されます$ $は、したがって、元の式は次のようになる
    。$$ \ sum_ 1} = X ^ {N- \ sum_ ^ {Y} 1、M = \左([\ NXのFRAC] [\マイFRAC]を[GCD(X、Y)= = 1] \右)$$
  • $ [GCD(x、y)のために == 1] $ 我々はすぐにメビウス$ \和の\ limits_ {D |の性質の関数で置き換えると考えることができます GCD(i、j)は}ミュー\(D)$、 そして、このような性質を持っています。$ D | GCD(I、 J)\ IFF D | I とD | j個の$それは次のようになります
    。$$の\ sum_ 1} ^ {N-I = \ sum_ {J} = ^ 1 m個の\左([\ FRACのNI ] [\ FRAC MJ] \和\ limits_ {D | I 及びd | J}ミュー(D \ )\右)$$
  • N- $の除数として変化列挙$ dが$、$ Dの$の$後に変更することができ、$ D $は明らかに$ N $の上限です。それは次のようになります
    。$$ \ sum_ 1} ^ {N-D = \ MU(D)\ sum_ 1} ^ {N-I = \ sum_ {J} 1 ^ M = \左([D | IおよびD | J] [\ FRACニッケル] [\ FRAC MJ] \右)$$
  • 又有
    $$ \和\ limits_ {i = 1} ^ n個の\和\ limits_ {J = 1} ^ m個の\左([D | I且D | J] [\ FRACのNI] [\ FRACのMJ]右\ )= \和\ limits_ {i = 1} ^ {[\ FRACのND]} \和\ limits_ {J = 1} ^ {[\ FRACのMD]} [\ FRAC N {ID}] * [\ FRAC Mを{ JD}] $$

    派生:我々は見つけることができ、$ \和\ limits_ {i = 1} ^ n個の\和\ limits_ {J = 1} ^ M [D | iとD | j]が$、実用的かつ効果的なタプル$は、(i、 ^ {[\ FRACのMD]} $ $列挙タプルとJ)$、$ \和\ limits_ {i = 1} ^ {[\ FRACのND]} \和\ limits_ {= 1 J}( i、j)は同じくらいの数で$。値は、後者のタプル$ Dの$倍に元のサイズに。$ I、J $は、元の$ \のFRAC 1dとの$になったため、変換制限した後、我々は、元のアイテムの背面に$ d個の$にそれらを取る必要があります。

  • 次に、元の式は次のようになる
    。$$ \ sum_ 1} ^ {N-D = \ MU(D)\ SUM \ limits_ 1 = {I} ^ {[\ FRACのNd]} \ SUM \ = J {limits_ 1} ^ {[\ FRACのMD ]} [\ FRAC N {ID}] * [\ FRACのM {JD}] $$
  • このとき、後者の式の$ \用和\ limits_ {i = 1} ^ {[\ FRACのND]} \和\ limits_ {J = 1} ^ {[\ FRACのMD]} [\ FRAC N {ID} ] * [\ FRACのM {JD }] $ 明らかに二つに転置で乗算することができる:$ \和\ limits_ {I = 1} ^ {[\ FRACのND]} [\ FRACのN {ID}] \和\ limits_ {J = 1 } ^ {[\ FRACのMD]} [\ FRACのM {JD}] $、 それは元の式のようになります
    。$$ \ sum_ 1} ^ {N-D = \ MU(D) \和\ limits_ {i = 1 } ^ {[\ FRACのND]} [\ FRAC N {ID}] \和\ limits_ {J = 1} ^ {[\ FRACのMD]} [\ FRACのM {JD}] $$
  • それがここで観察される$ \和\ limits_ {i = 1} ^ {[\ FRACのND]} [\ FRAC N {ID}] \和\ limits_ {J = 1} ^ {[\ FRACのMD]} [\ FRAC Mを{ JD}] $が前処理されます。そこ未知のは、両方の$ D $ですどこ$ nが前処理は、m個の$、、、少し難しいが$ dを列挙する必要があり、nは、m個の$、$ O(N ^ 3)$の複雑ことを意味するもの?私たちは、このアイデアを放棄する必要があり、考え方は固定観念することはできません。まず、我々は必要としない直接$ \合計\ limits_ {I = 1} ^ {[\ FRACのND]} [\ FRAC N {ID}] \合計\ limits_ {J = 1} ^ {[\ FRACのMD]} [\ FRACのM {JD}] $式全体前処理は、$ \和の\ limits_ {i = 1} ^ {[\ FRACのND]} [\ FRAC N {ID}] $と$ \ SUMのために分離することができます\ limits_ {J = 1} ^ {[\ FRACのMD]} [\ FRACのM {JD}] $前処理は、ここで列挙および$ dに低減することができ、複雑性の$ O(の$二種類をm個N ^ 2)$。しかし、今、彼らは決定された値の全範囲が、$ ND $スタイルの家は全体的に全体で、観察します。このような前処理の複雑さが$ O(nは\ sqrtのn)は、直接$ \ FRACの番目の$を列挙することができます$、合計複雑さがある:$ O(nは\ sqrtのN + N * T)$。
  • ただし、あまり複雑方法があり、我々はせ$のF(X)= \和 \ limits_ {i = 1} ^ X [\ FRAC第XI] $は、 元の式になる:
    $$ \ sum_ {D N- ^ 1} = \(\ MU(D)左F([\ FRACのNd]) F([\ FRAC MD])\右)$$
  • F $ $のいずれかが出ている上記、それにより$ O(1)$クエリによって前処理することができます。しかし、$ [\ FRACのND] $と$ [\ FRACのMD] $が$ [のL、R] $、区間$ [\ FRACのND] $と$ブロック、すなわちであることに留意され[\ FRACのMD] $は、Fの$([\ FRACのNd])の範囲ことが、決定されるF([\ FRACのMD])$が決定されます。だから、唯一のこのセクションF $([\ FRACのNd])を使用して F([\ FRAC MD])が、最終的に$ O(n個の複雑さを低減し、$ $ \ムー(D)$セクションを掛けたともできます\ SQRT N + \ SQRT {N} * T)$、 この問題があることができます
  • 実際に、あなたも少し最適化を行うことができます。我々は$ Fを定義する前に(X)= \合計 \ limits_ {I = 1} ^ X [\ FRACのXI] $は、 優秀な学生の数はすぐに、$ Fを見つけることができるかどうか(X)$は$ [1、であるX ]約$番号と番号、私たちは実際に前スクリーニングライン関数$ D $の場合、プレフィックスとが再びそれを行うことができます。このような最適化意志おそらく4倍高速
    ****
    ###注
    ****
    ###概要
  • 式$ \和のための\ limits_ {i = 1} ^ n個の\和\ limits_ {J = 1} ^ mは、[D | I およびD | j]が$は、それがあることは明らかであるに等しい$ \和\ limits_ {i = 1} ^ {[\ FRACのNd]} \ SUM \ limits_ {Jが= 1} ^ {[\ FRAC MD]}。1 = [\ FRACのNd] [\ FRAC MD] $、そしてために$ \和\ limits_ {I = 1 } ^ n個の\和の\ limits_ { J = 1 ^ M [D | I およびD | J]} [\ FRACのNi] [\ FRAC MJ] $、実際には、列挙の上限は、$ [\ FRAC NDを置換しました] $と$ [\ FRACのMD] $、私たちは、列挙されているすべての$ [D | IとD | j]が$タプルの$ [I、J] $ \ FRAC 1dとの$時間の$。我々は、次に、$ [\ FRAC Niは】計算実際に、我々は$ [\ N-FRAC {ID}]でなければならない計算に、[\ FRAC MJ]時間の$ $ ijは$ $ $ D時間を拡大する[\ m個のFRAC {JD}] $、これが
    。$$ \和\ limits_ 1} ^ {N-I = \ SUM \ limits_ 1} = {J ^ M [D | IおよびD | J]
    [\ FRACのNi] [\ FRAC MJ] = \ SUM \ limits_ {I = 1} ^ {[\ FRACのNd]} \ SUM \ limits_ {Jが= 1} ^ {[\ FRAC MD]} [\ FRAC N- {ID}] [\ FRAC mを{JD}] $$
  • そのような式のために
    $$ \ sum_ {i = 1} ^ n個の\ sum_ {J = 1} ^ MIJ = \左(\ sum_ {i = 1} ^ NI \右)* \左(\ sum_ {J = 複雑1} ^ MJ \右)$$この直接$(N ^ 2)O $は$ O(N)$に低減されます
  • ブロックは、最も古典的なプロセスの$ \和\ limits_ {i = 1} ^ N [\ FRAC第XI] $割り切れます。$ \合計が\ limits_ {i = 1} ^ NF([\ FRAC第XI])$、同じ$の各ブロックは[\ FRACのNI]は$が同じで、同じであってもよい。しかし、他の一般的な形態であります数え$ K $番目、オーバー$ K *のF [\ FRACのXI] $
  • の$ D $ふるい線形関数は、配列$ NUMを開くために必要である[I] $ $ I $素因数の最小数を記録生じます。処理、もし$ I%プライム[j] == 0 $、 即ち因子最小$プライムを含む[J] $、$ NUM [I] $は、 [I] + 1 $ $ NUMに更新されなければならない 、 そうでなければ、何の説明が、私は素因数が素数[J] $を$、および$プライム[J] $が新しい最小品質係数である。$ $が存在しない、ので、NUM = 1 [私は総理は[J]は*] エラーが発生しやすいここでは、覚えておくこと!!!)
    ****
    ### ACコード
#include<cstdio>
#include<algorithm>
using namespace std;

const int maxn = 50000 + 10;

bool no_prime[maxn];
int prime[maxn], mu[maxn], pre_mu[maxn], dd[maxn], num[maxn];
long long pre_dd[maxn];
int shai(int n)
{
   int cnt = 0;
   mu[1] = dd[1] = 1;

   for (int i = 2; i <= n; i++)
   {
       if (!no_prime[i])
           prime[++cnt] = i, mu[i] = -1, dd[i] = 2, num[i] = 1;

       for (int j = 1; j <= cnt && prime[j] * i <= n; j++)
       {
           no_prime[prime[j] * i] = 1;
           mu[prime[j] * i] = (i % prime[j] == 0) ? 0 : -mu[i];
           dd[prime[j] * i] = (i % prime[j] == 0) ? dd[i] / (num[i] + 1) * (num[i] + 2) : dd[i] * 2;
           num[prime[j] * i] = (i % prime[j] == 0) ? num[i] + 1 : 1;
           if (i % prime[j] == 0) break;
       }
   }

   for (int i = 1; i <= n; i++)
       pre_mu[i] = pre_mu[i - 1] + mu[i], pre_dd[i] = pre_dd[i - 1] + dd[i];
       
   return cnt;
}

long long cal2(int n, int m)
{
   int l = 1, r;
   long long ans = 0;
   while (l <= n)
   {
       r = min(n / (n / l), m / (m / l));
       ans += 1ll * (pre_mu[r] - pre_mu[l - 1]) * pre_dd[n / l] * pre_dd[m / l];
       l = r + 1;
   }
   return ans;
}

void solve()
{
   shai(maxn - 10);

   int t;
   scanf("%d", &t);
   while (t--)
   {
       int n, m;
       scanf("%d%d", &n, &m);
       if (n > m) swap(n, m);

       printf("%lld\n", cal2(n, m));
   }
}

int main()
{
   solve();
   return 0;
}

おすすめ

転載: www.cnblogs.com/dzzzh/p/11294710.html