1. 程式人生 > 實用技巧 >平凡的函式(素數篩)

平凡的函式(素數篩)

題目描述

某一天,你發現了一個神奇的函式\(f(x)\),它滿足很多神奇的性質:

  • \(f(1) = 1\)
  • \(f(p^c)=p \bigoplus c\)\(p\)為質數,\(\bigoplus\) 為異或)
  • \(f(ab) = f(a) * f(b)\)(a,b互質)

輸入

給定\(n\)

輸出

求出\(\sum_{i=1}^{n} f(i)\)

樣例輸入

23333

樣例輸出

171806766

solution

線性篩,然後對數質因數分解
剩下的就暴力乘法更新\(f\)陣列

code



#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;

inline int read(){
	int x = 0, w = 1;
	char ch = getchar();
	for(; ch > '9' || ch < '0'; ch = getchar()) if(ch == '-') w = -1;
	for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
	return x * w;
}

const int ss = 50000010;

int f[ss], prime[ss];
bool vis[ss];
int cnt;

signed main(){
	freopen("func.in", "r", stdin);
	freopen("func.out", "w", stdout);
	unsigned long long ans = 1;
	f[1] = 1;
	register int n = read();
	for(register int i = 2; i <= n; i++){
		if(!vis[i]) prime[++cnt] = i, f[i] = i ^ 1;
		for(register int j = 1; i * prime[j] <= n; j++){
			vis[i * prime[j]] = 1;
			if(i % prime[j] == 0){
				register int tmp = i, c = 1;
				while(tmp % prime[j] == 0) tmp /= prime[j], ++c;
				f[i * prime[j]] = f[tmp] * (prime[j] ^ c);
				break;
			}
			f[i * prime[j]] = f[i] * f[prime[j]];
		}
		ans += f[i];
	}
	cout << ans << endl;
	return 0;
}