数论::整除分块

题目链接:洛谷P3935

题目描述:

,求

 

 

输入格式

输入共一行,两个数,l,,r。

输出格式

输出共一行,一个数,为f(i),i∈(l,n)对998244353取模的结果。

分析:实际上,我们有

 

 

 反演d(i),我们有d(i)等价于

不妨先设函数f(x)为该式的朴素情况

即ans等价于

 

 

 即ans=f(r/i)-f((l-1)/j)

 对于f(x),不难看出一种O(n)的暴力算法,但是显然我们需要sqrt(n)的

我们可以先枚举观察r=10的情况,观察r/i的值

1   2  3  4  5  6  7  8  9  10
10 5  3  2  2  1  1  1  1  1

不难发现也不难证明,相同的数都是连续的,可以把它分成一块一块值相同的段。那么我们可以利用这个性质,对于每一块,将这个块的数字乘上块的长度,就可以求解这一块的和了。

首先是块的数量,在i在1到根号r之间时,最多有根号r个块,在大于根号r时,r/i<=根号r,所以一共最多有2√n种分块

当某一块的左端点为l,那么它的右端点r就是(r/(r/l))向下取整,至此,f(x)的求法为

ll ans=0;
for(ll l=1,r;l<=n;l=r+1)
{
    r=n/(n/l);
    ans+=(r-l+1)*(n/l);
}

所以Ans也可轻松解出

#include<bits/stdc++.h>
using namespace std;
int main()
{
    long long left,right;
    scanf("%lld%lld",&left,&right);
    long long sum1=0,sum2=0;
    for(long long l=1,r;l<=right;l=r+1)
    {
        r=right/(right/l);
        sum1=(sum1+(right/l)%998244353*((r-l+1)%998244353)%998244353)%998244353;
    }
    for(long long l=1,r;l<=left-1;l=r+1)
    {
        r=(left-1)/((left-1)/l);
        sum2=(sum2+((left-1)/l)%998244353*((r-l+1)%998244353)%998244353)%998244353;
    }
    printf("%lld\n",((sum1-sum2)%998244353+998244353)%998244353);
    return 0;
}

 



 

posted @ 2020-03-02 22:13  remarkableboy  阅读(254)  评论(0编辑  收藏  举报