数论分块

数论分块大致用于处理形如求Σ(1,n)  (k div i) 的问题

打表易得,(k div i)的值是线性的,因为向下取整,所以会出现值成段的现象,这样我们原先暴力的O(n)的算法可以得到优化

首先我们要知道一个定理

对于(k div i)而言最多有2√k个取值

证明:对于 i (1 <= i <= n, 且 i 是整数)而言,i 可以分成两种情况

  1. i <= √k , i 最多有 √k 个取值
  2. i >= √k , 那么 (k div i)<= √k,最多有√k个取值

所以我们可以拥有一个O(√k)的复杂度



对于怎么确定一个块值得左右边界,这里直接给出结论

对于一个块而言,假设左边界为LT,右边界为RT。那么有等式 RT = K / (K / LT)



所以我们就可以形如下式进行操作

 for(ll l = 1, r = 0 ; l <= n ; l = r + 1)
    {
        if(k / l) r = min(n, k/(k/l)) ;
        else r = n ;
        do something
    }

为了显得这篇文章不那么划水,所以还是要带一题例题

BZOJ 1257

题意就是让我们求 Σ(1,n) (k mod i)

那么怎么转换到今天的知识呢?

我们都知道 k mod i = k - (k div i) * i

原式 = n* k - Σ(1,n) (k div i) * i

对于一个值块(l , r)而言 (k div i) 的值是确定的,我们可以把它看成常数,这里假设成T,那么对于值块(l , r) 后一块可转换成 (k div i) * Σ(l,r) i 等差数列求和

这题就搞定了

#include <bits/stdc++.h>
using namespace std;
#define ll long long
ll n, k, ans = 0 ;
int main(int argc, char const *argv[])
{
    scanf("%lld %lld",&n,&k) ;
    ans = k * n ;
    for(ll l = 1, r = 0 ; l <= n ; l = r + 1)
    {
        if(k / l) r = min(n, k/(k/l)) ;
        else r = n ;
        ans -= (k / l) * (r - l + 1) * (l + r) / 2ll ;
    }
    printf("%lld\n",ans) ;
    return 0;
}

原文地址:https://www.cnblogs.com/wifePI/p/12337615.html

时间: 2024-11-09 02:32:35

数论分块的相关文章

【bzoj2956】模积和 数论+分块

题目描述 求∑∑((n mod i)*(m mod j))其中1<=i<=n,1<=j<=m,i≠j. 输入 第一行两个数n,m. 输出 一个整数表示答案mod 19940417的值 样例输入 3 4 样例输出 1 题解 数论+分块 由于直接求i≠j的情况比较难搞,所以我们可以先求出i可以等于j的和,然后再减去i等于j时的情况. 也就是求∑∑((n mod i)*(m mod j))-∑((n mod i)*(m mod i)). 然后再根据乘法分配律转化为∑(n mod i)*∑

【BZOJ1257】余数之和(数论分块,暴力)

[BZOJ1257]余数之和(数论分块,暴力) 题解 Description 给出正整数n和k,计算j(n, k)=k mod 1 + k mod 2 + k mod 3 + - + k mod n的值,其中k mod i表示k除以i的余数.例如j(5, 3)=3 mod 1 + 3 mod 2 + 3 mod 3 + 3 mod 4 + 3 mod 5=0+1+0+3+3=7 Input 输入仅一行,包含两个整数n, k. Output 输出仅一行,即j(n, k). Sample Input

数论分块 【数学】

数论分块 数论分块也是很重要哦(dalao说以后莫比乌斯反演要用到) 经典栗子: for i=1~n  求 ∑x=(n/i)  (注:这里()表示为下取整) 普通人一般暴力,复杂度 O(n) 这里就要用到数论分块. 我们可以模拟一下, 发现 x 在一定的区间内值不变. 这里就可以分块了.把值不变的每一块左端点.右端点算出来,就可以等差数列一起求和了. 这只是数论分块入门应用,后续待填坑... 推荐裸题:BZOJ2956 模积和 原文地址:https://www.cnblogs.com/Frank

数论分块之整除分块

前言 最近在学莫比乌斯反演,然而只看懂了莫比乌斯函数,然后反演看着一脸懵逼,最后只看懂了数论分块里面的一个分支内容(也是莫比乌斯反演的前置姿势),整除分块 于是写一篇博文记录一下整除分块 整除分块 整除分块是用于快速处理形似 \[ \sum_{i=1}^{n}{\lfloor \frac{n}{i} \rfloor} \] 的式子的方法 很显然,这个可以\(O(n)\)得到答案.但是,在某些题目中,毒瘤出题人将数据加强到了\(10^{10}\)以上,这个时候我们就无法通过\(O(n)\)的解法来

数论分块与整除相

引理一 $$\forall a,b,c\in\mathbb{Z},\left\lfloor\frac{a}{bc}\right\rfloor=\left\lfloor\frac{\left\lfloor\frac{a}{b}\right\rfloor}{c}\right\rfloor$$ 略证: \begin{split} &\frac{a}{b}=\left\lfloor\frac{a}{b}\right\rfloor+r(0\leq r<1)\\ \Rightarrow &\le

# [银联初赛]码队弟弟的求和(数论-分块求和)

[银联初赛]码队弟弟的求和(数论-分块求和) 题链(计蒜客) 思路: 平方之和公式:\(1^2+2^2+...+n^2=\frac{n*(n+1)*(2*n+1))}{6}\),前缀和处理 分块求和思想: \(\lfloor \frac{n}{i} \rfloor\)对于每一个值,可能有多个\(i\)对应,把这些\(i\)分在同一块,累加的时候直接使用乘积代替加法 int res=0; for(int l=1,r;l<=n;l=r+1){ r=n/(n/l); res+=(n/i*(r-l+1)

余数(数论分块)

题目描述: 题解: 首先容易想到:当 i > n 时,n mod i = n 所以如果 m > n , ans+=((m-n)%mod)*(n%mod)%mod; m=n; 接下来考虑 i<=n 的情况: 后面这个东西很明显可以用数论分块算,时间复杂度是O(sqrt(N)) 但我当时做的时候还没有学数论分块,所以代码十分丑陋 #include<iostream> #include<cstdio> #include<cmath> using namesp

[BZOJ4815][CQOI4815]小Q的表格 数论+分块

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4815 题目中所给条件中的(a,a+b)和(a,b)的关系很瞩目. 然后大家都知道(a,b)=(a,a-b)=(a,a+b),于是观察(猜)一下这个表格与gcd的关系. 可以发现每次修改(a,b)会影响到所有(i,j)=(a,b)的点,并且关系为f(i,j)=(i/a)*(j/b)*f(a,b). 所以只需要知道f(g,g)的值记为f(g),就能推出其他的值. 然后慢慢推推推大概可以推到这

bzoj 1257 [CQOI2007]余数之和——数论分块

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1257 \( n\%i = n - \left \lfloor n/i \right \rfloor * i \) 注意 n<k 时当前块的右端点可能超过 n ! #include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; in