题意
求,答案膜素数
数据范围:
题解
设
如果所以欧拉函数和狄利克雷卷积,可以知道(我一开始也没反应过来,可以设为
进一步推导)
,
可以整除分块求,问题就变为化解
(特指杜教筛操作)
设,
为积性函数,
由杜教筛
那么
就可以快速求得前缀积了(预处理范围取)
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <unordered_map>
using namespace std;
using LL = long long;
const int MAXN = 8e6 + 5;
LL N, P;
bool noprime[MAXN];
int prime[MAXN], cnt_p, phi[MAXN];
void Euler_Sieve(int top);
LL pre[MAXN];
unordered_map<LL, LL> sum;
LL inv_2, inv_6;
LL getpre(LL);
LL qpow(LL, LL);
LL getsum(LL, int);
int main(){
cin >> P >> N;
inv_2 = (P + 1) / 2, inv_6 = qpow(6, P - 2);
Euler_Sieve(MAXN - 5);
LL ans = 0;
LL l, r;
for(l = 1; l <= N; l = r + 1){
r = N / (N / l);
LL tmp = getpre(r) - getpre(l - 1);
tmp = (tmp % P + P) % P;
LL x = getsum(N / l, 3);
tmp = tmp * x % P;
ans = (ans + tmp) % P;
}
cout << ans << endl;
return 0;
}
LL getpre(LL n){
if(n <= MAXN - 5) return pre[n] % P;
if(sum[n]) return sum[n];
LL l, r, res;
res = getsum(n, 3);
for(l = 2; l <= n; l = r + 1){
r = n / (n / l);
LL tmp = (getsum(r, 2) - getsum(l - 1, 2) + P) % P;
res -= getpre(n / l) * tmp % P; res %= P;
}
res = (res + P) % P;
return sum[n] = res;
}
LL qpow(LL x, LL n){
LL res = 1;
while(n){
if(n & 1) res = res * x % P;
x = x * x % P;
n >>= 1;
}
return res;
}
void Euler_Sieve(int top){
int i, j;
phi[1] = 1;
for(i = 2; i <= top; i++){
if(!noprime[i])
prime[++cnt_p] = i, phi[i] = i - 1;
for(j = 1; j <= cnt_p && prime[j] * i <= top; j++){
noprime[prime[j] * i] = true;
if(i % prime[j] == 0){
phi[prime[j] * i] = phi[i] * prime[j];
break;
}
phi[prime[j] * i] = phi[i] * (prime[j] - 1);
}
}
for(j = 1; j <= top; j++)
pre[j] = (pre[j - 1] + 1LL * phi[j] * j % P * j % P) % P;
}
LL getsum(LL n, int op){
n %= P;
if(op == 1)
return n * (n + 1) % P * inv_2 % P;
else if(op == 2)
return n * (n + 1) % P * (2 * n + 1) % P * inv_6 % P;
else
return getsum(n, 1) * getsum(n, 1) % P;
}