题意:设 f ( x ) f(x) f(x) 表示圆心在(0,0) ,半径为 x x x 的圆上整点个数,求 ∑ i = 1 n f ( i ) k \displaystyle\sum_{i = 1}^nf(i)^k i=1∑nf(i)k
求圆上整点个数:半径固定情况下求圆上整点个数
参考视频:大佬讲解 一看就会
参考题解:大佬题解
把系数 4 提出来:
a
n
s
=
4
k
∑
i
=
1
n
h
(
i
)
k
\displaystyle ans = 4^k\sum_{i = 1}^nh(i)^k
ans=4ki=1∑nh(i)k
因为质因子的贡献可以单独计算,
h
(
i
)
h(i)
h(i) 是一个积性函数,25筛时根据提取的最小质因子是
4
n
+
1
4n + 1
4n+1 类型还是
4
n
+
3
4n + 3
4n+3 类型 乘上这种质因子的贡献。
当最小质因子是
4
n
+
1
4n + 1
4n+1 类型时:
a
n
s
=
a
n
s
+
(
2
e
+
1
)
k
∗
(
s
u
m
(
n
p
e
+
e
≠
1
)
)
ans = ans + (2e + 1)^k*(sum(\frac{n}{p^e} + e\neq1))
ans=ans+(2e+1)k∗(sum(pen+e=1))
当最小质因子是
4
n
+
3
4n + 3
4n+3 类型时:
a
n
s
=
a
n
s
+
s
u
m
(
n
p
e
)
+
e
≠
1
ans = ans + sum(\frac{n}{p^e}) + e\neq 1
ans=ans+sum(pen)+e=1
每一步素数的贡献:
如果该素数是
4
n
+
1
4n + 1
4n+1 类型,
a
n
s
+
3
k
ans + 3^k
ans+3k
如果该素数是
4
n
+
3
4n + 3
4n+3 类型 或者该素数为 2,
a
n
s
+
1
ans + 1
ans+1
由此需要筛出
4
n
+
1
4n + 1
4n+1的素数个数以及
4
n
+
3
4n + 3
4n+3 的素数个数
令
g
1
(
n
,
j
)
g1(n,j)
g1(n,j) 表示 :n 以内,i 是素数或 i 的最小素因子大于
p
j
p_j
pj,i 是
4
n
+
1
4n + 1
4n+1 类型的数
令
g
3
(
n
,
j
)
g3(n,j)
g3(n,j) 表示 :n 以内,i 是素数或 i 的最小素因子大于
p
j
p_j
pj,i 是
4
n
+
3
4n + 3
4n+3 类型的数
g 1 ( n , 0 ) = n − 1 4 , g 3 ( n , 0 ) = n + 1 4 g1(n,0) = \frac{n - 1}{4},g3(n,0) = \frac{n + 1}{4} g1(n,0)=4n−1,g3(n,0)=4n+1
令
s
u
m
1
(
p
)
sum1(p)
sum1(p) 表示 p 以内
4
n
+
1
4n + 1
4n+1 的质数个数,
s
u
m
3
(
p
)
sum3(p)
sum3(p) 表示 p 以内
4
n
+
3
4n + 3
4n+3 的质数个数
当提取的最小质因子
p
p
p 是
4
n
+
1
4n + 1
4n+1 类型时:
g
1
(
n
)
=
g
1
(
n
p
)
−
s
u
m
1
(
p
)
g1(n) = g1(\frac{n}{p}) - sum1(p)
g1(n)=g1(pn)−sum1(p)
g
3
(
n
)
=
g
3
(
n
p
)
−
s
u
m
3
(
p
)
g3(n) = g3(\frac{n}{p}) - sum3(p)
g3(n)=g3(pn)−sum3(p)
当提取的最小质因子
p
p
p 是
4
n
+
3
4n + 3
4n+3 类型时:
g
1
(
n
)
=
g
3
(
n
p
)
−
s
u
m
3
(
p
)
g1(n) = g3(\frac{n}{p}) - sum3(p)
g1(n)=g3(pn)−sum3(p)
g
3
(
n
)
=
g
1
(
n
p
)
−
s
u
m
1
(
p
)
g3(n) = g1(\frac{n}{p}) - sum1(p)
g3(n)=g1(pn)−sum1(p)
对 g1而言:因为提取的质因子模4余3,整个数要模4余1,所以剩余的部分也是模4余3(
3
∗
3
%
4
=
1
3 * 3 \% 4 = 1
3∗3%4=1)
对 g3 同理
再次证明,25筛无论是 g(n,j) 还是 s(n,j) 都可以筛一些非积性的东西,本质上是dp,只要考虑好贡献的转移就可以筛,也因此25筛更加灵活,并不是一套板子就能解决的事情
由于数据量达到了
1
0
11
10^{11}
1011,一不小心就会T掉,需要优化一些东西
对于贡献部分的
k
k
k 次幂,指数
e
e
e 的值不会太大(不会超过 200),小范围预处理部分数值的 k 次幂,复杂度为
n
3
4
log
n
\frac{n^{\frac{3}{4}}}{\log n}
lognn43
将 l o n g l o n g long long longlong 运算改为 i n t int int 运算,利用 a d d , s u b , m u l add,sub,mul add,sub,mul 函数减少取摸的次数以降低常数
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e6 + 10;
int num,tot;
bool ispri[maxn];
int pri[maxn],sum1[maxn],sum2[maxn];
ll w[maxn];
int g1[maxn],g2[maxn],id1[maxn],id2[maxn],sqr,val[maxn];
ll n,k;
int mod;
inline int add(int x, int y) {
x += y;
if (x >= mod) {
x -= mod;
}
return x;
}
inline int sub(int x, int y) {
x -= y;
if (x < 0) {
x += mod;
}
return x;
}
inline int mul(int x, int y) {
return (long long) x * y % mod;
}
inline void sieve(int n) {
ispri[0] = ispri[1] = true;
num = 0;
for (int i = 2; i <= n; i++) {
if (!ispri[i]) {
pri[++num] = i;
sum1[num] = sum1[num - 1] + (i % 4 == 1);
sum2[num] = sum2[num - 1] + (i % 4 == 3);
}
for (int j = 1; j <= num && i * pri[j] <= n; j++) {
ispri[i * pri[j]] = true;
if (i % pri[j] == 0) break;
}
}
}
inline int fpow(int a,ll b) {
int r = 1;
while (b) {
if (b & 1) r = mul(r,a);
b >>= 1;
a = mul(a,a);
}
return r;
}
inline int S(ll x,int y) {
if (x <= 1 || pri[y] >= x) return 0;
int t = x <= sqr ? id1[x] : id2[n / x];
int ans = mul(sub(g1[t],sum1[y]),val[3]); //(4n + 1)质数的贡献
ans = add(ans,sub(g2[t],sum2[y])); //(4n + 3)质数的贡献
if (y == 0) ans++; //特判 2 的贡献
for (int i = y + 1; i <= num && 1ll * pri[i] * pri[i] <= x; i++) {
for (ll e = 1, pe = pri[i]; pe <= x; e++, pe = pe * pri[i]) {
if (pri[i] % 4 == 1) {
ans = add(ans,mul(val[2 * e + 1],add(S(x / pe,i),(e != 1))));
} else {
ans = add(ans,add(S(x / pe,i),(e != 1))); //2和高斯质数的贡献
}
}
}
return ans;
}
int main() {
scanf("%lld%lld%d",&n,&k,&mod);
sieve(maxn - 10);
sqr = sqrt(n);
for (int i = 1; i <= 500; i++)
val[i] = fpow(i,k);
for (ll i = 1,j; i <= n; i = j + 1) {
j = n / (n / i);
w[++tot] = n / i;
ll p = n / i;
g1[tot] = (p - 1) / 4 % mod;
g2[tot] = (p + 1) / 4 % mod;
if (p <= sqr) id1[p] = tot;
else id2[j] = tot;
}
for (int i = 1; i <= num; i++) {
for (int j = 1; j <= tot && 1ll * pri[i] * pri[i] <= w[j]; j++) {
ll t = w[j] / pri[i];
int k = t <= sqr ? id1[t] : id2[n / t];
if (pri[i] % 4 == 1) {
g1[j] -= sub(g1[k],sum1[i - 1]);
g2[j] -= sub(g2[k],sum2[i - 1]);
} else if (pri[i] % 4 == 3) {
g1[j] -= sub(g2[k],sum2[i - 1]);
g2[j] -= sub(g1[k],sum1[i - 1]);
}
if (g1[j] < 0) g1[j] += mod;
if (g2[j] < 0) g2[j] += mod;
}
}
printf ("%d\n",mul(add(S(n,0),1),fpow(4,k)));
return 0;
}