loj #6053 简单的函数 min_25筛

\(\color{#0066ff}{ 题目描述 }\)

某一天,你发现了一个神奇的函数\(f(x)\),它满足很多神奇的性质:

  1. \(f(1)=1\)
  2. \(f(p^c)=p \oplus c\)\(p\) 为质数,\(\oplus\) 表示异或)。
  3. \(f(ab)=f(a)f(b)\)\(a\)\(b\) 互质)。

你看到这个函数之后十分高兴,于是就想要求出 \(\sum\limits_{i=1}^n f(i)\)

由于这个数比较大,你只需要输出 \(\sum\limits_{i=1}^n f(i) \bmod (10^9+7)\)

\(\color{#0066ff}{输入格式}\)

一行一个整数 \(n\)

\(\color{#0066ff}{输出格式}\)

一行一个整数 \(\sum\limits_{i=1}^n f(i) \bmod 1000000007\)

\(\color{#0066ff}{输入样例}\)

6
    
233333
    
9876543210

\(\color{#0066ff}{输出样例}\)

16
  
179004642
  
895670833

\(\color{#0066ff}{数据范围与提示}\)

对于\(30\%\)的数据,\(n \leq 100\)

对于\(60\%\)的数据,\(n \leq 10^6\)

对于\(100\%\)的数据,\(1 \leq n \leq 10^{10}\)

\(\color{#0066ff}{ 题解 }\)

min_25筛,我们先找到\(f(p)\)

不难发现\(f(p)\)=\(p \oplus 1\)

对于除了2以外的质数\(f(p)=p-1,f(2)=3\)

可以把2当成其它来算,最后+2就行了

还是项\(\varphi\)一样拆项,注意贡献的统计,\(f(p^c)=p\oplus c\)

#include<bits/stdc++.h>
#define LL  long long
LL in() {
	char ch; LL x = 0, f = 1;
	while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
	for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
	return x * f;
}
const int maxn = 2e6 + 100;
const int mod = 1e9+7;
LL g0[maxn], g1[maxn], a[maxn];
LL n, m, sqt;
LL pri[maxn], tot;
int getid(LL x) { return x <= sqt? x : m - n / x + 1; }
LL getans(LL a, int b) {
	if(a < pri[b]) return 0;
	LL ans = (((g1[getid(a)] - g1[getid(pri[b - 1])]) % mod) - (g0[getid(a)] - g0[getid(pri[b - 1])]) % mod) % mod ;
	for(int i = b; i <= tot && (LL)pri[i] * pri[i] <= a; i++)
		for(LL x = pri[i], f = 1; x * pri[i] <= a; x *= pri[i], f++)
			(ans += (getans(a / x, i + 1) * (pri[i] ^ f) % mod) + (pri[i] ^ (f + 1)) ) %= mod;
	return ans;
}
signed main() {
	sqt = sqrt(n = in());
	for(LL i = 1; i <= n; i = a[m] + 1)
		a[++m] = n / (n / i), g0[m] = ((a[m] % mod) - 1) , g1[m] = (((a[m] % mod) * ((a[m] % mod) + 1)) / 2 - 1) ;
	for(LL i = 2; i <= sqt; i++) {
		if(g0[i] != g0[i - 1]) {
			pri[++tot] = i;
			LL sqr = i * i;
			for(int j = m; a[j] >= sqr; j--) {
				int id = getid(a[j] / i);
				(g0[j] -= g0[id] - g0[i - 1]) %= mod;
				(g1[j] -= i * (g1[id] - g1[i - 1]) % mod) %= mod;
			}
		}
	}
	printf("%lld\n", ((getans(n, 1) + 1 + (n > 1) * 2)) % mod);
	return 0;
}
posted @ 2019-01-18 08:22  olinr  阅读(229)  评论(0编辑  收藏  举报