除法分塊學習筆記


\(\\\)

除法分塊


求以\(N\)為被除數,在\([0,N]\)的范圍內,將所得的商向下取整相同的所有除數區間。

  • \(N\in [0,10^9]\)

這個問題其實有\(\text O(\sqrt N)\)的解決方案,即除法分塊。

我們先給出做法,在證明正確性和復雜度。

\(\\\)

做法


維護兩個變量\(L,R\),代表當前除數區間為閉區間\([L,R]\)\(L\)初始值為\(1\)

然后在\(L\le N\)時循環進行下面的過程:

  • \(t=\lfloor\frac{N}{L}\rfloor\)
  • 當前答案區間的右端點\(R=\lfloor\frac{N}{t}\rfloor\)
  • \(L=R+1\)

\(\\\)

正確性證明


開始時左端點是\(1\)顯然是沒有問題的,而以后的每一次操作\(L=R+1\),因此,我們只需要證明每次的\(R\)都為正確的即可。

首先\(\lfloor\frac{N}{t}\rfloor\)一定是屬於該除數區間的,所以我們只需要證明該數為區間上界。

反證法。設\(X=\lfloor\frac{N}{t}\rfloor\)不是我們想要得到的\(R\),那么至少有\(X+1\)屬於答案區間。

於是有\(\lfloor\frac{N}{X+1}\rfloor=t\),因為是下取整,於是有\(N\ge t\times (X+1)\),於是有\(\lfloor\frac{N}{t}\rfloor\ge\big(\lfloor\frac{t\times (X+1)}{t}\rfloor=X+1\big)\)

而根據定義有\(X=\lfloor\frac{N}{t}\rfloor\),於是有\(X\ge X+1\),與事實相悖。

\(\\\)

復雜度證明


分情況討論。

當所選除數\(\le \sqrt N\) 時,顯然這一部分的除數區間不會超過\(\sqrt N\) 個。

當所選除數\(\ge \sqrt N\)時,得到的商\(\le \sqrt N\),商不超過\(\sqrt N\)種,所以除數區間也不會超過\(\sqrt N\)個。

於是總時間復雜度\(\text O(\sqrt N)\)

\(\\\)

\(\\\)

一類求和式的推導


給出兩個數列\(A,B\)和一個整數\(N\),其中\(A\)的下標范圍為\([1,N]\)\(B\)的下標范圍為\([0,N)\)

定義下表范圍為\([1,N]\)的數列\(C\),試求出所有的\(C_i\)\(\begin{align}C_i=\sum_{j=1}^i A_{\lfloor\frac{i}{j}\rfloor}\times B_{i\%j}\end{align}\)

  • \(N\in [1,10^5]\)

\(\\\)

\(Part\ 1:\ A_i=1,B_i=i\)


\(\begin{align}C_i=\sum_{j=1}^i A_{\lfloor\frac{i}{j}\rfloor}\times B_{i\%j}=\sum_{j=1}^i A_{\lfloor\frac{i}{j}\rfloor}\times B_{i-\lfloor\frac{i}{j}\rfloor\times j}=\sum_{j=1}^i \big(i-\lfloor\frac{i}{j}\rfloor\times j\big)=\sum_{j=1}^i i-\sum_{j=1}^i \lfloor\frac{i}{j}\rfloor\times j\end{align}\)

左一半求和為\(i^2\)

右一半求和時,考慮對於一個除法分塊的區間\([L,R]\),這一段區間累加的答案為\(t\times \frac{(L+R)(R-L+1)}{2}\)

\(\\\)

\(Part\ 2:\ A_i=i,B_i=i\)


\(\begin{align}C_i=\sum_{j=1}^i A_{\lfloor\frac{i}{j}\rfloor}\times B_{i\%j}=\sum_{j=1}^i \lfloor \frac i j\rfloor\times\big(i-\lfloor\frac{i}{j}\rfloor\times j\big)=\sum_{j=1}^i i\times\lfloor \frac i j\rfloor -\sum_{j=1}^i \lfloor\frac{i}{j}\rfloor^2\times j\end{align}\)

同樣對一個除法分塊的區間\([L,R]\)考慮,左一半對答案的貢獻為\(t\times i\times (r-l+1)\)

右一半對答案的貢獻為\(t^2\times \frac{(L+R)(R-L+1)}{2}\)

\(\\\)

\(Part\ 3:\ A,B\)隨機


\(\begin{align}C_i=\sum_{j=1}^i A_{\lfloor\frac{i}{j}\rfloor}\times B_{i\%j}=\sum_{j=1}^i A_{\lfloor\frac{i}{j}\rfloor}\times B_{i-\lfloor\frac{i}{j}\rfloor\times j}\end{align}\)

考慮一個除法分塊的區間\([L,R]\)對答案的貢獻為\(\begin{align}\sum_{j=L}^R A_{\lfloor\frac{i}{j}\rfloor}\times B_{i-\lfloor\frac{i}{j}\rfloor\times j}=A_{\lfloor\frac{i}{j}\rfloor}\times \sum_{j=L}^R B_{i-\lfloor\frac{i}{j}\rfloor\times j}\end{align}\)

於是左邊的\(A\)數列的答案是固定的,右邊的\(B\)數列的答案注意到可以表示成一個數列隔一段取一個數求和的形式。

於是\(N^2\)預處理\(f[i][j]\),表示從第\(i\)個位置開始(含第\(i\)個位置),向前每隔\(j\)個位置取一次的數求和,根據除法分塊的定義,\(i-t\times R\)應該為可選擇的最靠前的數字。於是對於一個除法分塊的區間\([L,R]\),有\(\sum_{j=L}^R B_{i-t\times j}=f[i-t\times L][t]\)

\(\\\)

\(Code\)


#include<cmath>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 100100
#define mod 123456789
#define R register
#define gc getchar
using namespace std;
typedef long long ll;

inline ll rd(){
  ll x=0; bool f=0; char c=gc();
  while(!isdigit(c)){if(c=='-')f=1;c=gc();}
  while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
  return f?-x:x;
}

ll n,a[N],b[N],c[N],f[N][350];

int main(){
  n=rd();
  for(R ll i=1;i<=n;++i) a[i]=rd();
  for(R ll i=1;i<=n;++i) b[i-1]=rd();
  for(R ll j=1;j<=340;++j)
    for(R ll i=0;i<=n;++i) f[i][j]=((i>=j?f[i-j][j]:0)+b[i])%mod;
  for(R ll i=1;i<=n;++i){
    for(R ll j=1;j<=340&&j<=i;++j) (c[i]+=a[i/j]*b[i%j])%=mod;
    for(R ll l=341,r;l<=i;l=r+1){
      ll t=i/l; r=i/t;
      (c[i]+=a[t]*f[i-t*l][t])%=mod;
    }
    printf("%lld\n",c[i]);
  }
  return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM