【2019集訓隊互測】整點計數(min_25篩)

傳送門


這裏稍微口胡記錄一下要點,詳細的自己去看xyx的集訓隊論文。

題解:

容易發現我們實際上要算的就是以 xx 爲斜邊的溝谷數的數量。

即統計有多少對 (y,z)(y,z) ,滿足 y2+z2=x2y^2+z^2=x^2

我們用高斯整數的角度來看,其實就是求 x2x^2 是多少個高斯整數與其共軛複數的乘積。

在這道題裏面,我們相當於是要對 x2x^2 在高斯整數環中進行質因數分解。

現在我們需要知道一個質數在高斯整數環裏面該如何被分解。

費馬平方和定理:奇質數 pp 可以表示爲兩個正整數 a,ba,b 的平方和,當且僅當 p1(mod4)p\equiv 1\pmod 4,並且這種表示在 a<ba<b 的時候是唯一的。

證明可以直接用高斯整數的理論,見xyx的集訓隊的論文。

2是一個特殊的質數,其分解爲 (1i)(1+i)(1-i)(1+i),是唯一的。

於是我們考慮 x2=i=1kpi2tix^2=\prod_{i=1}^kp_i^{2t_i} 能被表示成多少種不同的高斯整數與其共軛複數的乘積。

不難發現,%4=1\%4=1 的質數可以把分解出的指數任意分配,而其他質數只能對半分。

所以方案數爲 f(x)=4×i=1k(1+[p1(mod4)]2ti)f(x)=4\times\prod_{i=1}^k(1+[p\equiv 1\pmod 4]*2t_i)

除掉 44 之後是個積性函數,min_25篩即可。


代碼:

#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const

using std::cerr;
using std::cout;

int mod;
inline int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
inline int dec(int a,int b){return a-b<0?a-b+mod:a-b;}
inline int mul(int a,int b){ll r=(ll)a*b;return r>=mod?r%mod:r;}
inline void Inc(int &a,int b){a+=b-mod;a+=a>>31&mod;}
inline void Dec(int &a,int b){a-=b;a+=a>>31&mod;}
inline void Mul(int &a,int b){a=mul(a,b);}
inline int po(int a,ll b){int r=1;for(;b;b>>=1,Mul(a,a))if(b&1)Mul(r,a);return r;}
inline int MD(ll x){return x>=mod?x%mod:x;}

cs int N=1e6+7;

ll n,k;

int pw[100],sp[N];
int c1[2][N],c3[2][N];
int f[2][N];

int p[N],pc;
bool mrk[N];
void linear_sieve(){
	for(int re i=2;i<N;++i){
		if(!mrk[i])p[++pc]=i;
		for(int re j=1;i*p[j]<N;++j){
			mrk[i*p[j]]=true;
			if(i%p[j]==0)break;
		}
	}
}

int nn;
void min_25_sieves(){
	nn=sqrt(n);
	for(int re i=1;i<=nn;++i){
		c1[0][i]=(i-1)/4;
		c3[0][i]=(i+1)/4; 
		c1[1][i]=MD((n/i-1)/4);
		c3[1][i]=MD((n/i+1)/4);
	}int ct1=0,ct3=0;
	for(int re j=2;p[j]<=nn;++j){
		int p=::p[j],w1=nn/p;
		int w2=std::min<ll>(nn,n/p/p);
		if((p&3)==1){
			for(int re i=1;i<=w1;++i){
				Dec(c1[1][i],dec(c1[1][i*p],ct1));
				Dec(c3[1][i],dec(c3[1][i*p],ct3));
			}for(int re i=w1+1;i<=w2;++i){
				Dec(c1[1][i],dec(c1[0][n/i/p],ct1));
				Dec(c3[1][i],dec(c3[0][n/i/p],ct3));
			}for(int re i=nn;i>=(ll)p*p;--i){
				Dec(c1[0][i],dec(c1[0][i/p],ct1));
				Dec(c3[0][i],dec(c3[0][i/p],ct3));
			}++ct1;
		}else {
			for(int re i=1;i<=w1;++i){
				Dec(c1[1][i],dec(c3[1][i*p],ct3));
				Dec(c3[1][i],dec(c1[1][i*p],ct1));
			}for(int re i=w1+1;i<=w2;++i){
				Dec(c1[1][i],dec(c3[0][n/i/p],ct3));
				Dec(c3[1][i],dec(c1[0][n/i/p],ct1));
			}for(int re i=nn;i>=(ll)p*p;--i){
				Dec(c1[0][i],dec(c3[0][i/p],ct3));
				Dec(c3[0][i],dec(c1[0][i/p],ct1));
			}++ct3;
		}
	}for(int re i=1;i<=nn;++i){
		f[0][i]=add(c3[0][i],mul(c1[0][i],pw[3]));
		f[1][i]=add(c3[1][i],mul(c1[1][i],pw[3]));
	}
}

int gf(ll n){
	return n<=nn?f[0][n]:f[1][::n/n];
}

int solve(ll n,int i){
	int ans=dec(gf(n),f[0][p[i-1]]);if(i==1)++ans; 
	auto f=[](int p,int t){return (p&3)==1?pw[t<<1|1]:1;};
	for(int re j=i;(ll)p[j]*p[j]<=n;++j)
		for(ll nw=p[j],t=1;nw*p[j]<=n;nw*=p[j],++t){
			Inc(ans,mul(solve(n/nw,j+1),f(p[j],t)));
			Inc(ans,f(p[j],t+1));
		}
	return ans;
}

void Main(){
	scanf("%lld%lld%d",&n,&k,&mod);
	for(int re i=1;i<=90;++i)pw[i]=po(i,k);
	linear_sieve();min_25_sieves();
	cout<<mul(pw[4],solve(n,1)+1)<<"\n";
}

inline void file(){
#ifdef zxyoi
	freopen("integral.in","r",stdin);
#endif
}signed main(){file();Main();return 0;} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章