Min25模板 LOJ6503

#include <bits/stdc++.h>
typedef long long ll;

const ll MOD = 1e9 + 7;
ll qp(ll a, ll b) {
	ll ret = 1;
	while (b) {
		if (b & 1)
			ret = ret * a % MOD;
		b /= 2;
		a = a * a % MOD;
	}
	return ret;
}
inline ll add(ll x, ll y) { return (x + y) % MOD; }
inline ll sub(ll x, ll y) { return (x - y + MOD) % MOD; }
inline ll mul(ll x, ll y) {
	if (x > MOD)
		x %= MOD;
	if (y > MOD)
		y %= MOD;
	return x * y % MOD;
}
inline ll inv(ll x) { return qp(x, MOD - 2); }
ll pref(ll x) { return mul(mul(x, x + 1), inv(2)); }

const int MAXN = 2e6 + 1000;
ll prime[MAXN] = { 0 }, phi[MAXN] = { 0 }, tot = 0;

ll presum[MAXN];

void euler() {
	phi[1] = 1;
	for (int i = 2; i < MAXN; i++) {
		if (!phi[i]) {
			prime[++tot] = i;
			phi[i] = i - 1;

			presum[tot] = add(presum[tot - 1], i);
		}
		for (int j = 1; j <= tot && i * prime[j] < MAXN; j++) {
			if (i % prime[j] == 0) {
				phi[i * prime[j]] = phi[i] * prime[j];
				break;
			}
			phi[i * prime[j]] = phi[i] * phi[prime[j]];
		}
	}
}

using namespace std;
/
int id1[MAXN], id2[MAXN];
ll F[MAXN], G[MAXN], val[MAXN];
ll n;
#define id(x) (x <= d ? id1[x] : id2[n / (x)])

ll S(ll x, int cnt) {  //第cnt个素数
	if (x <= 1ll || prime[cnt] > x)
		return 0;
	ll d = sqrt(n);
	ll ans = sub(sub(G[id(x)], F[id(x)]), sub(presum[cnt - 1], cnt - 1));
	// ans = G[i] - presum[i-1]
	// k[0~]
	
	if (cnt == 1) ans = add(ans, 2); // 2是偶数,如有涉及进行特判

	for (int i = cnt; i <= tot && 1ll * prime[i] * prime[i] <= x; i++) {
		for (ll e = 1ll, prod = prime[i]; 1ll * prod * prime[i] <= x; e++, prod *= prime[i])
			ans = add(ans, add(mul((prime[i] ^ e), S(x / prod, i + 1)), (prime[i] ^ (e + 1))));
		//  ans += S(x / prod, i + 1) * f(p^e) + f(p^(e+1))
		// prod = p ^ e
	}
	return ans;
}

// f[i] = prime[i]^k
void cal() {
	ll d = sqrt(n), cnt = 0;
	for (ll l = 1, r; l <= n; l = r + 1) {
		r = n / (n / l);
		val[++cnt] = n / l, id(val[cnt]) = cnt;
		G[cnt] = sub(pref(val[cnt]), 1);
		F[cnt] = sub(val[cnt], 1);
		// 将所有数都当素数,计算前缀和, 记得除去1
	}
	for (ll i = 1ll; i <= tot && 1ll * prime[i] * prime[i] <= n; i++) {
		for (ll j = 1ll; j <= cnt && 1ll * prime[i] * prime[i] <= val[j]; j++) {
			G[j] = sub(G[j], mul(prime[i], sub(G[id(val[j] / prime[i])], presum[i - 1])));
			F[j] = sub(F[j], sub(F[id(val[j] / prime[i])], i - 1));
			// G[j] = G[j] - f[i] * (G[id(val[j]/prime[i])] - presum[i-1])
		}
	}
}
///
int main() {
	euler();
	cin >> n;
	cal();
	// cout << G[1] <<" " << F[1]<< endl;
	cout << S(n, 1) + 1ll << endl;
	// 答案记得加1
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值