【51Nod 1239】欧拉函数之和

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1239
还是模板题。
杜教筛:$$S(n)=\frac{n(n+1)}{2}-\sum_{i=2}^nS\left(\left\lfloor\frac ni\right\rfloor\right)$$
基于质因子分解的筛法:详见2016年论文《积性函数求和的几种方法》(讲得很详细的~~~)
为什么我写的洲哥筛常熟巨大QAQ
杜教筛\(O\left(n^{\frac 23}\right)\)

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll N = 1E10;
const int UP = 3981071;
const int mo = 1000000007;
const int ni2 = 500000004;

int phi[UP + 3], prime[UP + 3], num = 0, sum[UP + 3];
bool notp[UP + 3];

void Euler_shai() {
	sum[1] = phi[1] = 1;
	for (int i = 2; i <= UP; ++i) {
		if (!notp[i]) {
			prime[++num] = i;
			phi[i] = i - 1;
		}
		for (int j = 1, pro; j <= num && (pro = prime[j] * i) <= UP; ++j) {
			notp[pro] = true;
			if (i % prime[j] == 0) {
				phi[pro] = phi[i] * prime[j];
				break;
			} else
				phi[pro] = phi[i] * phi[prime[j]];
		}
		sum[i] = (sum[i - 1] + phi[i]) % mo;
	}
}

struct HashTable {
	static const int p = 1000007;
	ll val[p], ref[p];
	HashTable() {memset(ref, -1, sizeof(ref));}
	
	void add(ll pos, ll nu) {
		int tmp = pos % p;
		while (ref[tmp] != -1) {
			if (ref[tmp] == pos) return;
			++tmp; if (tmp == p) tmp = 0;
		}
		ref[tmp] = pos;
		val[tmp] = nu;
	}
	
	ll query(ll pos) {
		int tmp = pos % p;
		while (ref[tmp] != pos) {++tmp; if (tmp == p) tmp = 0;}
		return val[tmp];
	}
} HT;

ll Sum(ll x) {
	return x <= UP ? sum[x] : HT.query(x);
}

void DJ_shai(ll n) {
	for (ll i = n, y; i >= 1; i = n / (y + 1)) {
		y = n / i;
		if (y <= UP) continue;
		ll ret = 0;
		for (ll j = 2, l, pre = 1; j <= y; ++j) {
			l = y / j;
			j = y / l;
			ret = (ret + Sum(l) * ((j - pre) % mo) % mo) % mo;
			pre = j;
		}
		HT.add(y, (y % mo * ((y + 1) % mo) % mo * ni2 % mo - ret + mo) % mo);
	}
}

main() {
	Euler_shai();
	ll top;
	scanf("%lld", &top);
	DJ_shai(top);
	printf("%lld\n", Sum(top));
	return 0;
}

基于质因子分解的筛法\(O\left(\frac{n^{\frac 34}}{\log n}\right)\)

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 1E10;
const int UP = 1E5;
const int mo = 1000000007;
const int ni2 = 500000004;

bool notp[UP + 3];
ll G0[UP * 2 + 3], G1[UP * 2 + 3], F[UP * 2 + 3], J[UP * 2 + 3];
int prime[UP + 3], sum_prime[UP + 3], sum_phi[UP + 3], phi[UP + 3], sum_p[UP + 3];
int pre[UP * 2 + 3], num = 0, ma[UP + 3];

void Euler_shai(int n) {
	phi[1] = sum_phi[1] = 1;
	for (int i = 2; i <= n; ++i) {
		if (!notp[i]) {
			prime[++num] = i;
			sum_prime[num] = (sum_prime[num - 1] + i) % mo;
			phi[i] = i - 1;
			sum_p[i] = (sum_p[i - 1] + i - 1) % mo;
			ma[i] = num;
		} else {
			sum_p[i] = sum_p[i - 1];
			ma[i] = ma[i - 1];
		}
		for (int j = 1, pro; j <= num && (pro = i * prime[j]) <= n; ++j) {
			notp[pro] = true;
			if (i % prime[j] == 0) {
				phi[pro] = 1ll * phi[i] * prime[j] % mo;
				break;
			} else
				phi[pro] = 1ll * phi[i] * phi[prime[j]] % mo;
		}
		sum_phi[i] = (sum_phi[i - 1] + phi[i]) % mo;
	}
}

struct HashTable {
	static const int ppp = 2333333;
	ll ref[ppp]; int val[ppp];
	void clr() {memset(ref, -1, sizeof(ref)); ref[0] = val[0] = 0;}
	
	void add(ll pos, int nu) {
		int tmp = pos % ppp;
		while (ref[tmp] != -1) {++tmp; if (tmp == ppp) tmp = 0;}
		ref[tmp] = pos; val[tmp] = nu;
	}
	
	int query(ll pos) {
		int tmp = pos % ppp;
		while (ref[tmp] != pos) {++tmp; if (tmp == ppp) tmp = 0;}
		return val[tmp];
	}
} HT;

#define maa(x) (x >= sqc ? num : ma[x])

ll ZY_shai(ll n) {
	int cnt = 0, sqf = floor(sqrt(n)), sqc = ceil(sqrt(n));
	
	HT.clr();
	for (ll i = n, y; i >= 1; i = n / (y + 1)) {
		J[++cnt] = (y = n / i);
		HT.add(y, cnt);
		G0[cnt] = y;
		G1[cnt] = y % mo * ((y + 1) % mo) % mo * ni2 % mo;
		pre[cnt] = 0;
	}
	
	ll pp, delta;
	for (int i = 1, p = prime[i]; i <= num; p = prime[++i]) {
		pp = 1ll * p * p;
		for (int j = cnt; j >= 1 && J[j] >= pp; --j) {
			int id = HT.query(J[j] / p);
			delta = max(G0[id] - (i - 1 - pre[id]), 1ll);
			G0[j] -= delta;
			delta = (G1[id] - ((sum_prime[min(i - 1, maa(J[id]))] - sum_prime[pre[id]] + mo) % mo) + mo) % mo;
			G1[j] = (G1[j] - p * delta % mo + mo) % mo;
			pre[j] = i;
		}
	}
	
	for (int j = cnt; j >= 1; --j) {
		G0[j] = max(G0[j] - (num - pre[j]), 1ll);
		G1[j] = (G1[j] - ((sum_prime[maa(J[j])] - sum_prime[pre[j]] + mo) % mo) + mo) % mo;
	}
	
	ll ans = 0;
	for (int i = 1; i < sqc; ++i) {
		int id = HT.query(n / i);
		ans = (ans + (1ll + G1[id] - G0[id] + mo) % mo * phi[i] % mo) % mo;
	}
	
	ll prep = 0, sqrprep;
	for (int j = 1; j <= cnt; ++j) F[j] = 1;
	for (int i = num, p = prime[i]; i >= 1; p = prime[--i]) {
		pp = 1ll * p * p;
		for (int j = cnt; j >= 1 && J[j] >= pp; --j) {
			ll J_j = J[j];
			if (J_j < sqrprep) {
				if (J_j >= prep) F[j] = (1 + sum_p[min(J_j, 1ll * sqf)] - sum_p[prep - 1] + mo) % mo;
				else F[j] = 1;
			}
			int id = HT.query(J_j / p);
			if (J[id] < sqrprep) {
				if (J[id] >= prep) delta = (1 + sum_p[min(J[id], 1ll * sqf)] - sum_p[prep - 1] + mo) % mo;
				else delta = 1;
			} else
				delta = F[id];
			F[j] = (F[j] + (p - 1) * delta % mo) % mo;
			
			ll pic = pp;
			while (J_j >= pic) {
				id = HT.query(J_j / pic);
				if (J[id] < sqrprep) {
					if (J[id] >= prep) delta = (1 + sum_p[min(J[id], 1ll * sqf)] - sum_p[prep - 1] + mo) % mo;
					else delta = 1;
				} else
					delta = F[id];
				F[j] = (F[j] + pic / p * (p - 1) % mo * delta % mo) % mo;
				pic *= p;
			}
		}
		prep = p; sqrprep = pp;
	}
	
	return ((ans + F[cnt]) % mo - sum_phi[sqc - 1] + mo) % mo;
}

int main() {
	ll top;
	scanf("%lld\n", &top);
	Euler_shai((int) sqrt(top));
	printf("%lld\n", ZY_shai(top));
	return 0;
}
posted @ 2017-01-08 08:26  abclzr  阅读(588)  评论(0编辑  收藏  举报