• 【51Nod 1239】欧拉函数之和


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

    #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
    ", Sum(top));
    	return 0;
    }
    

    基于质因子分解的筛法(Oleft(frac{n^{frac 34}}{log n} ight))

    #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
    ", &top);
    	Euler_shai((int) sqrt(top));
    	printf("%lld
    ", ZY_shai(top));
    	return 0;
    }
    
  • 相关阅读:
    MYSQL连接不上100061错误
    最小生成树
    装载问题
    贪心算法-- 纪念品分组
    折腾日记----「乱七八糟的过程」
    LeetCode ---- 474. 一和零「二维01背包」
    Erlang TCP 实例
    Erlang 入门 ---- 基础(一)
    SpringBoot ---- Spring Security
    LeetCode----1026. 节点与其祖先之间的最大差值
  • 原文地址:https://www.cnblogs.com/abclzr/p/6261391.html
Copyright © 2020-2023  润新知