题意:设 表示圆心在(0,0) ,半径为 的圆上整点个数,求
求圆上整点个数:半径固定情况下求圆上整点个数
参考视频:大佬讲解 一看就会
参考题解:大佬题解
把系数 4 提出来:
因为质因子的贡献可以单独计算,
是一个积性函数,25筛时根据提取的最小质因子是
类型还是
类型 乘上这种质因子的贡献。
当最小质因子是
类型时:
当最小质因子是
类型时:
每一步素数的贡献:
如果该素数是
类型,
如果该素数是
类型 或者该素数为 2,
由此需要筛出
的素数个数以及
的素数个数
令
表示 :n 以内,i 是素数或 i 的最小素因子大于
,i 是
类型的数
令
表示 :n 以内,i 是素数或 i 的最小素因子大于
,i 是
类型的数
令
表示 p 以内
的质数个数,
表示 p 以内
的质数个数
当提取的最小质因子
是
类型时:
当提取的最小质因子
是
类型时:
对 g1而言:因为提取的质因子模4余3,整个数要模4余1,所以剩余的部分也是模4余3(
)
对 g3 同理
再次证明,25筛无论是 g(n,j) 还是 s(n,j) 都可以筛一些非积性的东西,本质上是dp,只要考虑好贡献的转移就可以筛,也因此25筛更加灵活,并不是一套板子就能解决的事情
由于数据量达到了
,一不小心就会T掉,需要优化一些东西
对于贡献部分的
次幂,指数
的值不会太大(不会超过 200),小范围预处理部分数值的 k 次幂,复杂度为
将 运算改为 运算,利用 函数减少取摸的次数以降低常数
代码:
#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;
}