数论分块()-其他
数论分块()
数论分块
数论分块
也叫整除分块
是用于快速处理类似于
式子的一种方法
复杂度:\(O(\sqrt{n})\)
思想阐述:以向下取整为例
对于\(\lfloor \frac{n}{i}\rfloor\),来说,它的值是呈块状递减分布的,至多有\(2\sqrt{n}\)个块
这些块的分布规律是:
对于一个块内的一个点\(l\),我们可以得到块的右端点为\(\lfloor \frac{n}{\lfloor \frac{n}{i} \rfloor} \rfloor\)
写成代码就是
int get(int l){return n/(n/l);}
非常的\(so\) \(easy\)
那么我们要求的 \(\sum_{i=1}^n \lfloor \frac{n}{i} \rfloor\)
也就迎刃而解了
for(int i=1;i<=n;i++){
int r=get(i);
ans+=(n/i)*(r-i+1);
i=r;
}
还有一个性质:
来一道例题吧:
余数之和(CQOI2007)
题意简述:给定\(n,k\)求:
注意到\(k \bmod i=k-\lfloor \frac{k}{i} \rfloor \times i\)
所以
由于数论分块,我们设\(\sum_{i=1}^n \lfloor \frac{k}{i} \rfloor\)分成了\(m\)个块,各个块的左右端点记作\(L_i,R_i(i\in [1,m])\)
则原式子可化为:
综上所述,答案即为:
\(Code:\)
cin>>n>>k;
ans=n*k;
for(int x=1,gx;x<=n;x=gx+1){
gx=k/x?min(k/(k/x),n):n;
ans-=(k/x)*(x+gx)*(gx-x+1)/2;
}
cout<<ans;
数论分块
数论分块
也叫整除分块
是用于快速处理类似于
式子的一种方法
复杂度:\(O(\sqrt{n})\)
思想阐述:以向下取整为例
对于\(\lfloor \frac{n}{i}\rfloor\),来说,它的值是呈块状递减分布的,至多有\(2\sqrt{n}\)个块
这些块的分布规律是:
对于一个块内的一个点\(l\),我们可以得到块的右端点为\(\lfloor \frac{n}{\lfloor \frac{n}{i} \rfloor} \rfloor\)
写成代码就是
int get(int l){return n/(n/l);}
非常的\(so\) \(easy\)
那么我们要求的 \(\sum_{i=1}^n \lfloor \frac{n}{i} \rfloor\)
也就迎刃而解了
for(int i=1;i<=n;i++){
int r=get(i);
ans+=(n/i)*(r-i+1);
i=r;
}
还有一个性质:
来一道例题吧:
余数之和(CQOI2007)
题意简述:给定\(n,k\)求:
注意到\(k \bmod i=k-\lfloor \frac{k}{i} \rfloor \times i\)
所以
由于数论分块,我们设\(\sum_{i=1}^n \lfloor \frac{k}{i} \rfloor\)分成了\(m\)个块,各个块的左右端点记作\(L_i,R_i(i\in [1,m])\)
则原式子可化为:
综上所述,答案即为:
\(Code:\)
cin>>n>>k;
ans=n*k;
for(int x=1,gx;x<=n;x=gx+1){
gx=k/x?min(k/(k/x),n):n;
ans-=(k/x)*(x+gx)*(gx-x+1)/2;
}
cout<<ans;