余数(数论分块)

题目描述:

题解:

首先容易想到:当 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 namespace std;
typedef long long ll;
const ll mod=1e9+7;
ll n,m,ans;
ll l,r,h,t,cnt,sum;
int main(){
    scanf("%lld%lld",&n,&m);
    if(n<=m){
        ans+=((m-n)%mod)*(n%mod)%mod;
        ll sq=sqrt(n);
        for(ll i=1;i<=n/(sq+1);i++)
            ans=(ans+(n%i))%mod;//这一区间内的n%i没有特殊规律,只能硬算
        for(ll i=sq;i>0;i--){//此处i表示除完以后向下取整的结果
            l=n/(i+1)+1;r=n/i;//用n除以[l,r]区间内的数取整完结果均为i
            //统计 n mod 这些数的余数就是求等差数列:n-i*l,n-i*(l+1),...,n-i*r 的和
            h=n-l*i,t=n-r*i;//首项,末项
            cnt=r-l+1,sum=h+t;//项数,首项加末项的和
            if(cnt&1ll)sum>>=1;
            else cnt>>=1;//除以2
            if(l<=r) ans=(ans+(cnt%mod)*(sum%mod))%mod;
        }
    }
    else{
        ll sq=sqrt(n);//基本同上
        if(m<=(n/(sq+1))){
            for(ll i=1;i<=m;i++)
                ans=(ans+(n%i))%mod;
        }
        else{
            for(ll i=1;i<=n/(sq+1);i++)
                ans=(ans+(n%i))%mod;
            for(ll i=sq;i>0;i--){
                l=n/(i+1)+1;r=n/i;
                if(r>=m) r=m;
                h=n-l*i,t=n-r*i;
                cnt=r-l+1,sum=h+t;
                if(cnt&1ll)sum>>=1;
                else cnt>>=1;
                if(l<=r) ans=(ans+(cnt%mod)*(sum%mod))%mod;
                if(r==m) break;
            }
        }
    }
    printf("%lld",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/HarryPotter-fan/p/11378088.html

时间: 2024-11-09 00:39:50

余数(数论分块)的相关文章

【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

数论分块之整除分块

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

【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)*∑

数论分块 【数学】

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

数论分块与整除相

引理一 $$\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)

数论分块

数论分块大致用于处理形如求Σ(1,n)  (k div i) 的问题 打表易得,(k div i)的值是线性的,因为向下取整,所以会出现值成段的现象,这样我们原先暴力的O(n)的算法可以得到优化 首先我们要知道一个定理 对于(k div i)而言最多有2√k个取值 证明:对于 i (1 <= i <= n, 且 i 是整数)而言,i 可以分成两种情况 i <= √k , i 最多有 √k 个取值 i >= √k , 那么 (k div i)<= √k,最多有√k个取值 所以我

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

[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),就能推出其他的值. 然后慢慢推推推大概可以推到这