数论分块复习
数论分块复习
形如:
可以在
for(int l=1,r;l<=n;l=r+1)
{
r=n/(n/l);
ans+=(r-l+1)*(n/l);
}
如果不是裸的式子,可以先预处理前缀和来做(这就用得到杜教筛了)
例题:P1829
先用莫比乌斯处理。
对于式子
我们可以用数论分块来做
例题:P2260 模积和
求:
解:
考虑前面半段:
然后这个式子就是一个整除分块的式子了,“维护”出
int ans1=n*n%modn;
for(int l=1;l<=n;l=r+1)
{
r=(n/(n/l));
ans1=(ans1 - get_sum(l,r)*(n/l)%modn + modn)%modn;//get_sum 就是求 sigma(l,r);
}
考虑后半段:
注意数论分块的时候最好 r=min(n,n/(n/l)),这样子不会越界。(加就完事了,也不吃亏)
#include<bits/stdc++.h>
using namespace std;
const int MX=1*1000+100;
#define LL long long
#define inf 0x3f3f3f3f
#define modn 19940417
inline LL read()
{
LL x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-48;ch=getchar();}
return x*f;
}
LL n,m;
const LL inv2=9970209;
const LL inv6=3323403;
inline LL get_sum(LL l,LL r)
{
return (r+l)*(r-l+1)%modn*inv2%modn;
}
inline LL get_pf(LL l,LL r)
{
return ( ( r*(r+1)%modn*(2*r%modn+1)%modn*inv6%modn ) - ( (l-1)*(l)%modn*(2*l%modn-1)%modn*inv6%modn ) +modn )%modn;
}
LL bans,cans;
int main(int argc, char const *argv[])
{
//printf("%lld\n",get_pf(114514,1919810));
n=read(),m=read();
if(n>m) swap(n,m);
LL ans1=n*n%modn;
for(LL l=1,r;l<=n;l=r+1)
{
r=(n/(n/l));
ans1=(ans1 - get_sum(l,r)*(n/l)%modn + modn)%modn;
}
LL ans2=m*m%modn;
for(LL l=1,r;l<=m;l=r+1)
{
r=(m/(m/l));
ans2=(ans2 - get_sum(l,r)*(m/l)%modn + modn)%modn;
}
bans=ans1*ans2%modn;
//cout<<bans<<endl;
cans=(n*n%modn*m)%modn;
LL now=0;
for(LL l=1,r;l<=n;l=r+1)
{
r=min(n,(m/(m/l)));
now=(now + get_sum(l,r)*(m/l)%modn )%modn;
}
now=(now*n)%modn;
cans=(cans-now+modn)%modn;
now=0;
for(LL l=1,r;l<=n;l=r+1)
{
r=min(n,(n/(n/l)));
now=(now + get_sum(l,r)*(n/l)%modn )%modn;
}
now=(now*m)%modn;
cans=(cans-now+modn)%modn;
now=0;
for(LL l=1,r;l<=n;l=r+1)
{
r=min(n,min( (n/(n/l)) , (m/(m/l)) ));
now=(now + get_pf(l,r)*(n/l)%modn*(m/l)%modn );
}
cans=(cans+now)%modn;
bans=(bans-cans+modn)%modn;
cout<<bans<<endl;
return 0;
}
洛谷太逊了,公式有问题,直接复制到 Typora 里去看
updata:洛谷又不逊了。