传送门: HDU 5608
附一下tls整理的求积性函数前缀和的姿势,
应该是杜教筛
author: skywalkert
original article: http://blog.csdn.net/skywalkert/article/details/50500009
last update time : 2017-04-01
题解:
令 G(n) = n ^ 2 - 3 * n + 2
先反演得:
令:
然后从约数角度考虑对A(n)做出的贡献, 得
其中:
根据分块可以得到n / i在一段区间内是不变的
一段区间G(i)的和也可以用求和公式直接得到
那么现在就只要求M(n)
因此:
同样用分块来做, 可以用线性筛预处理n^(2/3)以内的M(i)
code:
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int N = 1000001;
const int mo = 2333333;
const ll mod = 1e9 + 7;
bool isPrime[N];
int prime[N];
ll mobius[N];
ll ans;
inline ll getG(ll x)
{//求和公式
ll mod1 = 6 * mod;
ll res = x * (x + 1) % mod1 * (2*x + 1) % mod1 / 6;
ll t = 3 * x * (x+1) % (2*mod) / 2;
t = mod - t % mod;
res = (res + t + x * 2) % mod;
return res;
}
void init()
{ //预处理M(i)
int cnt = 0;
memset(isPrime, true, sizeof isPrime);
isPrime[1] = false;
mobius[1] = 1;
// g[1] = 0;
for(int i = 2; i < N; ++i)
{
if(isPrime[i])
{
prime[++cnt] = i;
mobius[i] = -1;
}
for(int j = 1; j <= cnt && i * prime[j] < N; ++j)
{
isPrime[i * prime[j]] = false;
if(i % prime[j] == 0)
{
mobius[i * prime[j]] = 0;
break;
}
mobius[i * prime[j]] = -mobius[i];
}
}
for(int i = 2; i < N; ++i)
{
mobius[i] = ((mobius[i] + mobius[i - 1]) % mod + mod) % mod;
// g[i] = getG((ll)i);
}
}
ll n;
ll v[mo];
ll t[mo];
int last[mo], pre[mo];
int l;
void add(int x, ll y, ll z)
{
t[++l] = y;
pre[l] = last[x];
last[x] = l;
v[l] = z;
}
ll getSum(ll R, ll L)
{
return ((getG(R) - getG(L)) % mod + mod) % mod;
}
ll cal(ll x)
{
if(x < N)
{
return mobius[x];
}
int k = x % mo;
for(int i = last[k]; i; i = pre[i])
if(t[i] == x) return v[i];//hash做记忆化搜索
ll r;
ll ans = 1;
for(ll i = 2; i <= x; i = r + 1)//分块
{
ll tmp = x / i;
r = x / tmp;
ll res = cal(tmp) * (r - i + 1) % mod;
ans = ((ans - res) % mod + mod) % mod;
}
add(k, x, ans);
return ans;
}
ll Calc(ll x)
{
ll ans = 0;
ll r;
for(ll i = 1; i <= x; i = r + 1)
{
ll tmp = x / i;
r = x / tmp;
ll res = cal(tmp) * getSum(r, i - 1) % mod;
ans = ((ans + res) % mod + mod) % mod;
}
return ans;
}
int main()
{
init();
int t;
cin >> t;
while(t--)
{
cin >> n;
ll res = Calc(n);
cout << res << endl;
}
return 0;
}