HDU5608 function 【杜教篩】

題目描述

N23N+2=dnf(d)N^2-3N+2=\sum_{d|n}f(d)
i=1nf(i)  mod  1e9+7\sum_{i=1}^nf(i)~~mod~~1e9+7
多組數據,T500,N109T\le500,N\le10^9,至多5組數據 N>=106~N>=10^6

題目分析

杜教篩其實就是用狄利克雷卷積優化
n23n+2n^2-3n+2 看作 g(n)g(n)
那麼可看出 fI=gf*I=g
倘若用於卷積的其中一個函數(此處的II)和卷積後的函數(此處的gg)很好求前綴和,那麼就可以優化求卷積中的另一個函數的前綴和
i=1ng(i)=i=1ndif(d)I(id)           =i=1nd=1nif(d)I(i)\sum_{i=1}^ng(i)=\sum_{i=1}^n\sum_{d|i}f(d)*I({i\over d})\\~~~~~~~~~~~=\sum_{i=1}^n\sum_{d=1}^{\lfloor{n\over i}\rfloor}f(d)*I(i)
上式第二行中的ii實際上是在枚舉第一行中iidd的幾倍
這樣就使得dd連續,便於分塊優化,記i=1nf(i)=F(n)\sum_{i=1}^nf(i)=F(n)
i=1ng(i)=i=1ndif(d)I(id)           =i=1nF(ni)I(i)\sum_{i=1}^ng(i)=\sum_{i=1}^n\sum_{d|i}f(d)*I({i\over d})\\~~~~~~~~~~~=\sum_{i=1}^nF(\lfloor{n\over i}\rfloor)*I(i)
i=1i=1移到左邊,g移到右邊,得到
F(n)I(1)=F(n)=i=1ng(i) i=2nF(ni)I(i)F(n)*I(1)=F(n)\\=\sum_{i=1}^ng(i) ~-\sum_{i=2}^nF(\lfloor{n\over i}\rfloor)*I(i)
g(i)可以O(1)求,F用分塊優化,O(n34)O(n^{3\over 4})

但是還是會TLE,需要線性篩出n106n\le10^6的F,時間複雜度可以降到O(n23)O(n^{2\over 3})

fI=gf(Iμ)=gμfe=gμf*I=g\\ f*(I*\mu)=g*\mu\\ f*e=g*\muf(n)=(gμ)(n)            =dng(d)μ(nd)f(n)=(g*\mu)(n)\\~~~~~~~~~~~~=\sum_{d|n}g(d)\mu(\frac nd)
枚舉d,暴力更新d的倍數,O(nlnn),其實上述也是莫比烏斯的另類推導。。。

總的來說就是 卷積+線性篩(用到了莫比烏斯反演)

#include<cstdio>
#include<map>
using namespace std;
const int mod = 1e9+7, N = 1000000, inv3 = 333333336;
map<int,int>F;
int T,n,sum[N+5],mu[N+5],p[N+5];
bool v[N+5];
void Prime()
{
	mu[1]=1;int cnt=0;
	for(int i=2;i<=N;i++)
	{
		if(!v[i]) p[++cnt]=i,mu[i]=-1;
		for(int j=1,k;j<=cnt&&p[j]*i<=N;j++)
		{
			v[k=p[j]*i]=1;
			if(i%p[j]==0) {mu[k]=0;break;}
			mu[k]=-mu[i];
		}
	}
	for(int i=1;i<=N;i++)
	{
		int x=(1ll*i*i-3*i+2)%mod;
		for(int j=i;j<=N;j+=i)
			sum[j]=(sum[j]+x*mu[j/i])%mod;
	}
	for(int i=1;i<=N;i++) sum[i]=(sum[i]+sum[i-1])%mod;
}
int solve(int n)
{
	if(n<=N) return sum[n];
	if(F.count(n)) return F[n];
	int ret=(1ll*n*(n+1)%mod*(n-4)%mod*inv3+2*n)%mod;
	for(int i=2,j;i<=n;i=j+1)
	{
		j=n/(n/i);
		ret=(ret-1ll*solve(n/i)*(j-i+1))%mod;
	}
	return F[n]=ret;
}
int main()
{
	Prime();
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d",&n);
		printf("%d\n",(solve(n)+mod)%mod);
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章