本来在赛场上推完了公式,不是实现难度有点高,20多分钟根本rush不完,我太难了。
对于和
来说当
的时候只需要做质数个数和以及质数和两个
就可以解决问题了,当
时我们直接暴力就行了
//author Forsaken
#define Hello the_cruel_world!
#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<utility>
#include<cmath>
#include<climits>
#include<deque>
#include<functional>
#include<numeric>
#define lowbit(x) ((x) & (-(x)))
#define FRIN freopen("C:\\Users\\Administrator.MACHENI-KA32LTP\\Desktop\\1.in", "r", stdin)
#define FROUT freopen("C:\\Users\\Administrator.MACHENI-KA32LTP\\Desktop\\1.out", "w", stdout)
#define FAST ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define outd(x) printf("%d\n", x)
#define outld(x) printf("%lld\n", x)
#define outu(x) printf("%u\n", x)
#define memset0(arr) memset(arr, 0, sizeof(arr))
#define il inline
using namespace std;
typedef unsigned int ui;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const int maxn = 1e5;
const int INF = 0x7fffffff;
const int mod = 998244353;
const double eps = 1e-7;
const double Pi = acos(-1.0);
il int read_int() {
char c;
int ret = 0, sgn = 1;
do { c = getchar(); } while ((c < '0' || c > '9') && c != '-');
if (c == '-') sgn = -1; else ret = c - '0';
while ((c = getchar()) >= '0' && c <= '9') ret = ret * 10 + (c - '0');
return sgn * ret;
}
il ll read_ll() {
char c;
ll ret = 0, sgn = 1;
do { c = getchar(); } while ((c < '0' || c > '9') && c != '-');
if (c == '-') sgn = -1; else ret = c - '0';
while ((c = getchar()) >= '0' && c <= '9') ret = ret * 10 + (c - '0');
return sgn * ret;
}
il ll quick_pow(ll base, ll index, ll p) {
ll res = 1;
while (index) {
if (index & 1)res = res * base % p;
base = base * base % p;
index >>= 1;
}
return res;
}
//线性筛
bool is_prime[maxn + 5];
int prime[maxn + 5], cnt;
ll sp[maxn + 5];
void init(int n) {
for (int i = 2; i <= n; ++i)is_prime[i] = true;
for (int i = 2; i <= n; ++i) {
if (is_prime[i]) {
++cnt;
prime[cnt] = sp[cnt] = i;
}
for (int j = 1; j <= cnt && i * prime[j] <= n; ++j) {
is_prime[i * prime[j]] = false;
if (i % prime[j] == 0)break;
}
}
for (int i = 1; i <= cnt; ++i)sp[i] = (sp[i] + sp[i - 1]) % mod;
}
//min筛
int m, id1[maxn + 5], id2[maxn + 5];
ll g1[2 * maxn + 5], g2[2 * maxn + 5], v[2 * maxn + 5], block;
ll n, inv;
void min25() {
block = sqrt(n);
init(block);
for (ll l = 1, r; l <= n; l = r + 1) {
r = n / (n / l);
v[++m] = n / l;
g1[m] = v[m] % mod - 1, g2[m] = (v[m] + 1) % mod * (v[m] % mod) % mod * inv % mod - 1;
if (v[m] <= block)id1[v[m]] = m;
else id2[n / v[m]] = m;
}
for (int i = 1; i <= cnt; ++i) {
for (int j = 1; j <= m && 1ll * prime[i] * prime[i] <= v[j]; ++j) {
int id = (v[j] / prime[i] <= block) ? id1[v[j] / prime[i]] : id2[n / (v[j] / prime[i])];
g1[j] -= (g1[id] - i + 1) % mod;
g1[j] %= mod;
g2[j] -= (sp[i] - sp[i - 1]) * (g2[id] - sp[i - 1]) % mod;
g2[j] %= mod;
}
}
}
ll solve(ll n) {
ll res = 0;
for (ll l = 1, r; l <= n; l = r + 1) {
r = n / (n / l);
int idr = ((r <= block) ? id1[r] : id2[n / r]), idl = (((l - 1) <= block) ? id1[l - 1] : id2[n / (l - 1)]);
res += (n / l) % mod * ((n + 1) % mod) % mod * ((g1[idr] - g1[idl]) % mod) % mod;
res -= (n / l) % mod * ((n / l + 1) % mod) % mod * inv % mod * ((g2[idr] - g2[idl]) % mod) % mod;
res %= mod;
}
for (int i = 1; i <= cnt; ++i) {
ll v = 1ll * prime[i] * prime[i];
for (; v <= n; v = v * prime[i]) {
res += (n + 1) % mod * ((n / v) % mod) % mod;
res -= (n / v) % mod * ((n / v + 1) % mod) % mod * inv % mod * (v % mod) % mod;
res %= mod;
}
}
if (res < 0)res += mod;
return res;
}
int main()
{
inv = quick_pow(2, mod - 2, mod);
n = read_ll();
min25();
ll res = solve(n);
outld(res);
return 0;
}
京公网安备 11010502036488号