Loj#6052. 「雅礼集训 2017 Day11」DIV

scb tql!!!!!!!!!!!

不复读一遍scb博客了。简略写一些。

假如要算\(\lfloor \frac{n}{i} \rfloor\)处的函数值,如果能在\(O(\sqrt n)\)的时间内算出单点函数值,那么复杂度为

\[\sum\limits_{x=1}^{\sqrt n}\sqrt{\frac{n}{x}}+\sqrt x=\sqrt n\int_0^{\sqrt n}x^{-\frac{1}{2}}dx+\int_0^{\sqrt n}x^{\frac{1}{2}}dx=O(n^{\frac{3}{4}}) \]

基于这个,我们来考虑转化之后的式子

\[\sum\limits_{d=1}^{\sqrt n}\mu(d)d\sum\limits_{g=1}^{\lfloor \frac{n}{d^2} \rfloor}g\sum\limits_{a=1}^{\sqrt{\lfloor\frac{n}{gd^2}\rfloor}}a\sum\limits_{b=1}^{\sqrt{\lfloor\frac{n}{gd^2}\rfloor}}\lfloor\frac{n}{gd^2(a^2+b^2)}\rfloor \]

考虑设\(f(m)=\sum\limits_{a=1}^{\sqrt a}a\sum\limits_{b=1}^{\sqrt b}\lfloor\frac{m}{a^2+b^2}\rfloor\)这玩意不好求,再来一个\(g(m)=\sum\limits_{a=1}^{\sqrt m}a\sum\limits_{b=1}^{\sqrt m}[a^2+b^2\leq m]\)。这样就可以通过枚举\(\lfloor\frac{m}{a^2+b^2}\rfloor\),用上文所说的时间复杂度求出\(f\)

再来一个\(h(m)=\sum\limits_{i=1}^mf(\lfloor\frac{m}{i}\rfloor)i\)。这个就再来一个上文所说时间复杂度求出。用\(h\)即可算出最终答案。

其实这本质上就是杜教筛。

\(b=0\)就是约数和,随便求一求。总时间复杂度\(O(n^{\frac{3}{4}})\)

然后再丧心病狂卡卡常就能卡过去了。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
using namespace std;
typedef unsigned long long ll;
#define N 200102
const int p=1004535809,iv=(p+1)>>1;
ll n,b[N][2],sqr;
int tot,c[N],f[N],id1[N],id2[N],h[N],prim[N],cnt,mu[N],fjd;
ll tr[N];
bool isp[N];
inline void upd(int &x,int y){x+=x+y>=p?y-p:y;}
inline int S(ll x){if(x>=p)x%=p;return (x*(x+1)/2)%p;}
inline int calf(int i)
{
	ll td=n/b[i][0];int la=0;
		for(register ll ii=1,j;ii<=td;ii=j+1)
		{ll dd=td/ii;
			j=td/dd;
			int pos=j>=fjd?id1[n/j]:id2[tr[j]];
			upd(f[i],dd*(c[pos]-c[la]+p)%p);la=pos;
		}
	return f[i];
}
inline int cal(ll x)
{
	int pos=x<=sqr?id1[x]:id2[n/x];
	if(h[pos]>=0)return h[pos];
	int ret=0;int la=0;
	for(register ll i=1,j;i<=x;i=j+1)
	{ll td=x/i;
		j=x/td;
		int pos=td<=sqr?id1[td]:id2[n/td];
		int ts=S(j);
		int sum=(ts-la+p)%p;la=ts;
		upd(ret,1ll*f[pos]*sum%p);
	}return h[pos]=ret;
}
int main()
{memset(h,-1,sizeof(h));
	for(int i=2;i<=200000;i++)isp[i]=1;mu[1]=1;
	for(int i=2;i<=200000;i++)
	{
		if(isp[i])prim[++cnt]=i,mu[i]=-1;
		for(int j=1;j<=cnt&&prim[j]*i<=200000;j++)
		{
			isp[prim[j]*i]=0;
			if(i%prim[j]==0){mu[prim[j]*i]=0;break;}
			mu[prim[j]*i]=-mu[i];
		}
	}
	scanf("%llu",&n);sqr=sqrt(n);
	for(ll i=1,j;i<=n;i=j+1)
	{ll td=n/i;
		j=n/td;
		b[++tot][0]=i,b[tot][1]=j;
		if(td<=sqr)id1[td]=tot;
		else id2[n/td]=tot;
		for(int ii=1;1ll*ii*ii<=j;ii++)
		{int te=sqrt(j-1ll*ii*ii);
			upd(c[tot],1ll*ii*te%p);
		}
	}
	ll l=1,r=n,mid;
	while(l<=r)
	{
		mid=(l+r)>>1;
		if(n/mid<=sqr)fjd=mid,r=mid-1;
		else l=mid+1;
	}
	for(int i=1;i<=min(100000*1ull,n);i++)tr[i]=n/(n/i);
	for(int i=1;i<=tot;i++)f[i]=calf(i);
	int ans=0;
	for(int i=1;1ll*i*i<=n;i++)
	{
		int te=1ll*(mu[i]+p)%p*i%p*cal(n/i/i)%p;
		upd(ans,te);
	}
	ans=2ll*ans%p;
	for(ll i=1,j;i<=n;i=j+1)
	{
		j=n/(n/i);
		int te=1ll*(n/i)%p*((i+j)%p)%p*((j-i+1)%p)%p*iv%p;
		upd(ans,te);
	}
	printf("%d\n",ans);
}
posted @ 2021-03-02 20:48  Lebron_Durant  阅读(134)  评论(0)    收藏  举报