HDU5608 function 【杜教筛】

版权声明:本文为博主原创文章,未经博主允许必须转载。 https://blog.csdn.net/C20181220_xiang_m_y/article/details/84840730

题目描述

N 2 3 N + 2 = d n f ( d ) N^2-3N+2=\sum_{d|n}f(d)
i = 1 n f ( i )    m o d    1 e 9 + 7 \sum_{i=1}^nf(i)~~mod~~1e9+7
多组数据, T 500 , N 1 0 9 T\le500,N\le10^9 ,至多5组数据   N > = 1 0 6 ~N>=10^6

题目分析

杜教筛其实就是用狄利克雷卷积优化
n 2 3 n + 2 n^2-3n+2 看作 g ( n ) g(n)
那么可看出 f I = g f*I=g
倘若用于卷积的其中一个函数(此处的 I I )和卷积后的函数(此处的 g g )很好求前缀和,那么就可以优化求卷积中的另一个函数的前缀和
i = 1 n g ( i ) = i = 1 n d i f ( d ) I ( i d )             = i = 1 n d = 1 n i f ( 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)
上式第二行中的 i i 实际上是在枚举第一行中 i i d d 的几倍
这样就使得 d d 连续,便于分块优化,记 i = 1 n f ( i ) = F ( n ) \sum_{i=1}^nf(i)=F(n)
i = 1 n g ( i ) = i = 1 n d = 1 n i f ( d ) I ( i )             = i = 1 n F ( n i ) I ( i ) \sum_{i=1}^ng(i)=\sum_{i=1}^n\sum_{d=1}^{\lfloor{n\over i}\rfloor}f(d)*I(i)\\~~~~~~~~~~~=\sum_{i=1}^nF(\lfloor{n\over i}\rfloor)*I(i)
i = 1 i=1 移到左边,g移到右边,得到
F ( n ) I ( 1 ) = F ( n ) = i = 1 n g ( i )   i = 2 n F ( n i ) 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 ( n 3 4 ) O(n^{3\over 4})

但是还是会TLE,需要线性筛出 n 1 0 6 n\le10^6 的F,时间复杂度可以降到 O ( n 2 3 ) O(n^{2\over 3})

f I = g f ( I μ ) = g μ f e = g μ f*I=g\\ f*(I*\mu)=g*\mu\\ f*e=g*\mu f ( n ) = ( g μ ) ( n )              = d n g ( d ) μ ( n d ) 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);
	}
}

猜你喜欢

转载自blog.csdn.net/C20181220_xiang_m_y/article/details/84840730
今日推荐