51nod1239(杜教筛)

题目

对正整数n,欧拉函数是小于或等于n的数中与n互质的数的数目。此函数以其首名研究者欧拉命名,它又称为Euler's totient function、φ函数、欧拉商数等。例如:φ(8) = 4(Phi(8) = 4),因为1,3,5,7均和8互质。

S(n) = Phi(1) + Phi(2) + ...... Phi(n),给出n,求S(n),例如:n = 5,S(n) = 1 + 1 + 2 + 2 + 4 = 10,定义Phi(1) = 1。由于结果很大,输出Mod 1000000007的结果。

 收起

输入

输入一个数N。(2 <= N <= 10^10)

输出

输出S(n) Mod 1000000007的结果。

输入样例

5

输出样例

10

解题思路:杜教筛模板题

代码:

#include
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 10;
const ll mod = 1000000007;
const ll inv = 500000004;
ll prime[maxn],mark[maxn],phi[maxn];

unordered_map M;
void gettable(){
	phi[1] = mark[1] = 1;
	for(int i = 2;i < maxn;++i){
		if(!mark[i])	prime[++prime[0]] = i,phi[i] = i - 1;
		for(int j = 1;j <= prime[0] && prime[j] * i < maxn;++j){
			mark[prime[j] * i] = 1;
			if(i % prime[j] == 0){
				phi[i * prime[j]] = phi[i] * prime[j];
				break;	
			}
			phi[i * prime[j]] = phi[i] * (prime[j] - 1);
		}
	}
	for(int i = 1;i < maxn;++i)	phi[i] = (phi[i] + phi[i - 1]) % mod;	
}

ll gets(ll n){
	if(n < maxn)	return phi[n];
	if(M.count(n))	return M[n];
	ll res = n % mod * ((n + 1) % mod) % mod * inv % mod,k;//注意在乘之前对(n+1)取模
	for(ll i = 2;i <= n;i = k + 1){
		k = n / (n / i);
		res = ((res - (k - i + 1) % mod * gets(n / i) % mod) % mod + mod) % mod;
	}
	M[n] = res;
	
	return res;
}

int main(){
	gettable();
	ll N;
	
	cin>>N;
	cout<

 

你可能感兴趣的:(数论,#,杜教筛,杜教筛,数论)