转载请注明出处,谢谢http://blog.csdn.net/bigtiao097?viewmode=contents
题意:
n2−3n+2=∑d|nf(d)
s(n)=∑ni=1f(i) 给定n,求 s(n)mod109+7 (1≤n≤109)
思路:
杜教筛的接近模板题,如果没做过杜教筛的题目的话,可以先看一下这两个题目
求莫比乌斯函数之和、求欧拉函数之和
继续给大家推荐唐老师的这篇文章,个人感觉讲的非常好,我就是在这里学的
对于这个题
n2−3n+2=∑d|nf(d)
所以就有
n×(n−1)×(n−2)3=∑i=1ni2−3i+2=∑i=1n∑d|if(d)=∑i=1n∑d=1⌊ni⌋f(d)=∑i=1ns(⌊ni⌋)
这样就得到了
s(n)=n×(n−1)×(n−2)3−∑i=2ns(⌊ni⌋)
典型的杜教筛,就可以直接做了
推导过程不明白的可以去看一下推荐的文章
关于复杂度的问题,具体可以看上面推荐的文章,这里稍微说一下
如果我们先提前筛选出了
n23
的
φ(n)
的前缀和,总体复杂度大概是
O(n23)
具体代码如下:
Result:Accepted
Memory:14900K
Time :1263MS
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int maxn = 1e6;
ll g[maxn];
int T;
ll n;
unordered_map<ll,ll> mp;
bool vis[maxn];
int prime[maxn];
int mu[maxn];
int tot;
ll calc(ll x)
{
if(x<maxn)return g[x];
if(mp.find(x)!=mp.end())
return mp[x];
ll ans = x*(x-1)%mod*(x-2)%mod*333333336%mod;
for(ll l=2,r; l<=x; l=r+1)
{
r=x/(x/l);
ans=(ans-calc(x/l)*(r-l+1)%mod+mod)%mod;
}
return mp[x]=ans;
}
void mobius()
{
memset(vis,0,sizeof vis);
mu[1] = 1;
tot = 0;
for(int i = 2; i <maxn; i++)
{
if( !vis[i] ){
prime[tot++] = i;
mu[i] = -1;
}
for(int j = 0; j < tot; j++)
{
if(i * prime[j] >=maxn) break;
vis[i * prime[j]] = true;
if( i % prime[j] == 0)
{
mu[i * prime[j]] = 0;
break;
}
else
mu[i * prime[j]] = -mu[i];
}
}
}
void init()
{
mobius();
for(int i=1;i<maxn;i++)
for(int j=i;j<maxn;j+=i)
g[j] = (g[j]+1LL*mu[j/i]*(i-1)*(i-2)%mod+mod)%mod;
// for(int i=1;i<maxn;i++)
// g[i] = 1LL*(i-1)*(i-2)%mod;
// for(int i=1;i<maxn;i++)
// for(int j=i+i;j<maxn;j+=i)
// g[j] = (g[j]-g[i]+mod)%mod;
// for(int i=2;i<maxn;i++)
// g[i] = (g[i]+g[i-1])%mod;
}
int main()
{
init();
scanf("%d",&T);
while(T--)
{
scanf("%lld",&n);
printf("%lld\n",calc(n));
}
}