HDU5608 function(杜教筛)

HDU5608 function(杜教筛)

题目大意

给出一个函数其满足
N 2 − 3 N + 2 = ∑ d ∣ N f ( d ) N^2-3N+2=\sum_{d|N}f(d) N23N+2=dNf(d)
∑ i = 1 n f ( i ) \sum_{i=1}^nf(i) i=1nf(i)

解题思路

很明显的杜教筛,它甚至帮你把需要构造的卷积给出来了,对着做就行了。可以发现原函数本质就是莫比乌斯函数卷积上那个多项式,为了方便求前缀和,得把多项式拆开和莫比乌斯函数卷积,这样卷积得结果就是积性函数了,就可以方便得线性求出了

AC代码

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int size=1e6+5;
const int mod=1e9+7;
int p[size],tot,mu[size];
int minn_prime[size];
bool prime[size];
int f2[size],f1[size];
int f[size];
int inv6;
unordered_map<int,int> mp;
int quick_pow(int a,int b){int ans=1;while(b){if(b&1) ans=1LL*ans*a%mod;a=1LL*a*a%mod;b>>=1;}return ans;}
void init()
{
    mu[1]=1;f2[1]=1;f1[1]=1;
    for(int i=1;i<size;i++) prime[i]=true;
    for(int i=2;i<size;i++)
    {
        if(prime[i])
        {
            p[++tot]=i;
            mu[i]=-1;
            minn_prime[i]=i;
            f1[i]=i-1;
            f2[i]=(1LL*i*i%mod-1+mod)%mod;
        }
        for(int j=1;j<=tot&&p[j]*i<size;j++)
        {
            prime[i*p[j]]=false;minn_prime[i*p[j]]=p[j];
            if(i%p[j]==0)
            {
                mu[i*p[j]]=0;
                f1[i*p[j]]=f1[i]*p[j];
                f2[i*p[j]]=1LL*f2[i]*p[j]%mod*p[j]%mod;
                break;
            }
            else {
                mu[i*p[j]]=-mu[i];
                f1[i*p[j]]=f1[i]*f1[p[j]];
                f2[i*p[j]]=1LL*f2[i]*f2[p[j]]%mod;
            }
        }
    }
    for(int i=1;i<size;i++) f[i]=(f2[i]-3LL*f1[i]+mod)%mod;
    f[1]=(f[1]+2)%mod;
    f[0]=0;
    for(int i=1;i<size;i++) f[i]=(f[i-1]+f[i])%mod;
    inv6=quick_pow(6,mod-2);
}
int Sum2(int n)
{
	return 1LL*n*(n+1)%mod*(2*n+1)%mod*inv6%mod;
}
int Sum1(int n)
{
	return 1LL*(n+1)*n/2%mod;
}
int S(int n)
{
	if(n<size) return f[n];
	if(mp.count(n)) return mp[n];
	int ans=(Sum2(n)-3LL*Sum1(n)+2*n)%mod;
	for(int l=2,r;l<=n;l=r+1)
	{
		r=n/(n/l);
		ans=(ans-1LL*(r-l+1)*S(n/l)%mod+mod)%mod;
	}
	return mp[n]=ans;
}
int main()
{
    init();
    int t;
    int n;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        if(n<size)
        {
            printf("%d\n",f[n]);
        }
        else
        {
            printf("%d\n",S(n));
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值