[硫化铂]数

题目概述在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

题解

首先有 n ⩽ 1 0 11 n\leqslant 10^{11} n1011的数据范围,大概是个筛子。

首先我们关注我们的判定条件: k = c 2 − a 2 − b 2 ( b + c = a ∧ a , b , c ∈ N + ) k=c^2-a^2-b^2(b+c=a\wedge a,b,c\in N^{+}) k=c2a2b2(b+c=aa,b,cN+)
化简一下,
k = ( b + d ) 2 − ( b − d ) 2 − b 2 = 4 b d − b 2 = b ( 4 d − b )   ( b ∈ ( d , 4 d ) ) k=(b+d)^2-(b-d)^2-b^2\\ =4bd-b^2=b(4d-b)\,(b\in(d,4d)) k=(b+d)2(bd)2b2=4bdb2=b(4db)(b(d,4d))我们相当于可以将可以将我们的的 k k k拆成 x ⋅ y x\cdot y xy,并且满足条件 y ∈ ( 0 , 3 x ) , 4 ∣ ( x + y ) y\in(0,3x),4|(x+y) y(0,3x),4(x+y)
显然如果我们直接筛这东西的话是 O ( n ln ⁡ n ) O\left(n\ln n\right) O(nlnn)的,但这个判定条件明显可以继续往下导出一些东西。
我们可以设 k = 2 a × b k=2^a\times b k=2a×b,其中, b b b是奇数。
我们考虑,当 a = 0 a=0 a=0时,如果 b b b不是质数,那么我们必然可以将 b b b拆成大的因数与小的因数,大的因数的三倍肯定大于小的因数。
所以,只有当 k k k为大于 2 2 2的质数时并且 k % 4 = 3 k\%4=3 k%4=3,只存在唯一一种的拆分方式 ( k , 1 ) (k,1) (k,1)满足条件。
而当 a = 1 a=1 a=1或者 a = 3 a=3 a=3,必然会导致 2 2 2分配的不均,不能使 4 ∣ a + b 4|a+b 4a+b
a = 2 a=2 a=2时,我们必须将给 x , y x,y x,y分别一个 2 2 2,这时,就没必要考虑它们各自模 4 4 4是多少了。
但这种情况下还是有我们上面的可拆分问题,所以这里限制的是 k k k是某个大于 2 2 2的质数的 4 4 4倍或 4 4 4
同样,我们 a = 4 a=4 a=4的时候也只存在两边都给 2 2 2 2 2 2的分配方式,同时需要保证 k k k是质数的 16 16 16倍或 16 16 16

所以我们最后要求的是 n n n以内模 4 4 4 3 3 3的质数,除 4 4 4是质数的数,除 16 16 16是质数的数以及 4 4 4 16 16 16
实际上就是模 4 4 4 3 3 3的质数数量与模 4 4 4 1 1 1的质数数量,这东西要算前缀和,不就是 min ⁡ _ 25 \min\_25 min_25筛嘛。
我们可以记录下这两者的前缀和,显然,每次我们乘上一个质数我们可以根据它关于 4 4 4的余数得到它在 min ⁡ _ 25 \min\_25 min_25中容斥的变化。很简单就可以得到只剩质数处取值的前缀和了。
由于我们本身就只要质数处,所以就没必要进行第二步了。由于 min ⁡ _ 25 \min\_25 min_25求了每个 ⌊ n i ⌋ \lfloor\frac{n}{i}\rfloor in处的前缀和,直接算答案就行。

时间复杂度 O ( n 3 4 ln ⁡ n ) O\left(\frac{n^{\frac{3}{4}}}{\ln n}\right) O(lnnn43)

源码

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<LL,LL> pii;
#define MAXN 500005
#define MAXM 1000005
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
#define reg register
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
void Add(int &x,int y,int p){x=add(x,y,p);}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1)t=1ll*a*t%p;a=1ll*a*a%p;s>>=1;}return t;}
int id1[MAXN],id2[MAXN],idx,prime[MAXN],cntp,n1,sum[MAXN][2];
LL n,a[MAXM];pii F[MAXM];
bool oula[MAXN];
void init(){
	for(int i=2;i<=n1;i++){
		if(!oula[i]){
			prime[++cntp]=i;
			sum[cntp][0]=sum[cntp-1][0]+(i%4==1);
			sum[cntp][1]=sum[cntp-1][1]+(i%4==3);
		}
		for(int j=1;1ll*i*prime[j]<=n1&&j<=cntp;j++){
			oula[i*prime[j]]=1;
			if(i%prime[j]==0)break;
		}
	}
}
int getId(LL x){if(!x)return 0;return x<=n/x?id1[x]:id2[n/x];}
int main(){
	//freopen("number.in","r",stdin);
	//freopen("number.out","w",stdout);	
	read(n);n1=sqrt(n);init();
	for(LL l=1,r;l<=n;l=r+1)r=n/(n/l),a[++idx]=n/l;
	for(int i=1;i<=idx;i++)(a[i]<=n/a[i]?id1[a[i]]:id2[n/a[i]])=i;
	for(int i=1;i<=idx;i++)F[i]=mkpr((a[i]-1)/4,(a[i]+1)/4);
	for(int i=2;i<=cntp;i++){
		LL tp=1ll*prime[i]*prime[i];
		if(prime[i]%4==1)
			for(int j=1;j<=idx&&a[j]>=tp;j++){
				LL t=a[j]/prime[i];int x=getId(t);
				F[j].fir-=F[x].fir-sum[i-1][0];
				F[j].sec-=F[x].sec-sum[i-1][1];
			}
		else for(int j=1;j<=idx&&a[j]>=tp;j++){
			LL t=a[j]/prime[i];int x=getId(t);
			F[j].fir-=F[x].sec-sum[i-1][1];
			F[j].sec-=F[x].fir-sum[i-1][0];
		} 
	}
	LL tmp1=F[getId(n)].sec;
	LL tmp2=F[getId(n>>2)].fir+F[getId(n>>2)].sec+(n>=4);
	LL tmp3=F[getId(n>>4)].fir+F[getId(n>>4)].sec+(n>=16);
	printf("%lld\n",tmp1+tmp2+tmp3);
	return 0;
}

谢谢!!!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值