LOJ传送门
题目描述
某一天,你发现了一个神奇的函数 f ( x ) f(x) f(x),它满足很多神奇的性质:
- f ( 1 ) = 1 f(1)=1 f(1)=1。
- f ( p c ) = p ⊕ c f(p^c)=p \oplus c f(pc)=p⊕c( p p p 为质数, ⊕ \oplus ⊕ 表示异或)。
- f ( a b ) = f ( a ) f ( b ) f(ab)=f(a)f(b) f(ab)=f(a)f(b)( a a a 与 b b b 互质)。
你看到这个函数之后十分高兴,于是就想要求出 ∑ i = 1 n f ( i ) \sum\limits_{i=1}^n f(i) i=1∑nf(i)。
由于这个数比较大,你只需要输出 ∑ i = 1 n f ( i )   m o d   ( 1 0 9 + 7 ) \sum\limits_{i=1}^n f(i) \bmod (10^9+7) i=1∑nf(i)mod(109+7)。
输入输出格式
输入格式
一行一个整数 n n n。
输出格式
一行一个整数 ∑ i = 1 n f ( i )   m o d   1000000007 \sum\limits_{i=1}^n f(i) \bmod 1000000007 i=1∑nf(i)mod1000000007。
输入输出样例
样例输入 1
6
样例输出 1
16
样例输入 2
233333
样例输出 2
179004642
样例输入3
9876543210
样例输出3
895670833
数据范围与提示
对于
30
%
30\%
30%的数据,
n
≤
100
n \leq 100
n≤100。
对于
60
%
60\%
60%的数据,
n
≤
1
0
6
n \leq 10^6
n≤106。
对于
100
%
100\%
100%的数据,
1
≤
n
≤
1
0
10
1 \leq n \leq 10^{10}
1≤n≤1010。
解题分析
首先质数除了 2 2 2以外 f ( p ) f(p) f(p)值都是 p − 1 p-1 p−1, 所以直接用 m i n 25 min25 min25筛筛出 p r i m e s u m primesum primesum和 p r i m e c o u n t primecount primecount ,然后特判 1 1 1和 2 2 2的情况了。
代码如下:
#include <cstdio>
#include <cmath>
#include <cstring>
#include <cctype>
#include <cstdlib>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define ll long long
#define MX 205000
#define MOD 1000000007
#define INV 500000004
int pcnt, dif, sqr;
ll n, val[MX];
int pri[MX], pc[MX], ps[MX], pfix[MX], id1[MX], id2[MX];
//pc for prime counting
//ps for prime sum
bool npr[MX];
void Sieve()
{
ll tar, buf;
for (R int i = 2; i <= sqr; ++i)
{
if (!npr[i]) pri[++pcnt] = i, pfix[pcnt] = (pfix[pcnt - 1] + i) % MOD;
for (R int j = 1; j <= pcnt; ++j)
{
tar = pri[j] * i;
if (tar > sqr) break;
npr[tar] = true;
if (!(i % pri[j])) break;
}
}
for (R ll lef = 1, rig; lef <= n; lef = rig + 1)
{
rig = n / (n / lef);
val[++dif] = n / lef;
if (val[dif] <= sqr) id1[val[dif]] = dif;
else id2[n / val[dif]] = dif;
pc[dif] = (val[dif] - 1) % MOD;
ps[dif] = ((val[dif] + 2) % MOD) * ((val[dif] - 1) % MOD) % MOD * INV % MOD;
}
for (R int i = 1; i <= pcnt; ++i)
{
for (R int j = 1; j <= dif && val[j] >= 1ll * pri[i] * pri[i]; ++j)
{
buf = val[j] / pri[i];
tar = buf <= sqr ? id1[buf] : id2[n / buf];
pc[j] = (pc[j] - pc[tar] + i - 1) % MOD;
ps[j] = ((ps[j] - 1ll * pri[i] * (ps[tar] - pfix[i - 1]) % MOD) % MOD + MOD) % MOD;
}
}
}
int S(R ll up, R int k)
{
if (up <= 1 || pri[k] > up) return 0;
ll tar, buf; int pw;
tar = up <= sqr ? id1[up] : id2[n / up];
int ret = ((1ll * ps[tar] - pc[tar] - pfix[k - 1] + k - 1) % MOD + MOD) % MOD;
for (R int i = k; i <= pcnt && 1ll * pri[i] * pri[i] <= up; ++i)
{
buf = pri[i], tar = buf * pri[i];
for (pw = 1; tar <= up; buf = tar, tar = tar * pri[i], ++pw)
(ret += (1ll * S(up / buf, i + 1) * (pri[i] ^ pw) % MOD + (pri[i] ^ (pw + 1)) % MOD) % MOD) %= MOD;
}
return k == 1 ? (ret + 2) % MOD : ret;
}
int main(void)
{
scanf("%lld", &n);
sqr = std::sqrt(n);
Sieve();
printf("%d", S(n, 1) + 1);
}