法里数列
- 性质1:连续三项为 b a 、 b + d a + c 、 d c \frac ba 、\frac{b+d}{a+c}、 \frac dc ab、a+cb+d、cd,且分子分母满足是互质的(真分数)
- 性质2:指定一个常数N,它的法里数列的项数为 φ ( N ) \varphi(N) φ(N),因此可以得到前缀和是: 2 + φ ( 2 ) + φ ( 3 ) + ⋯ + φ ( N ) 2+\varphi(2)+\varphi(3)+\dots+\varphi(N) 2+φ(2)+φ(3)+⋯+φ(N)
- 数列的中项永远是 1 2 \frac 12 21
- 任意两项 b a 和 d c \frac ba和\frac dc ab和cd 满足 a b s ( a d − b c ) = 1 abs(ad-bc)=1 abs(ad−bc)=1
- 项数公式: 2 + φ ( 2 ) + φ ( 3 ) + ⋯ + φ ( N ) ≈ 3 N 2 π 2 2+\varphi(2)+\varphi(3)+\dots+\varphi(N) \approx \frac {3N^2}{\pi ^2} 2+φ(2)+φ(3)+⋯+φ(N)≈π23N2 即, F n = 1 + ∑ i = 1 n φ ( i ) ≈ 3 N 2 π 2 F_n=1+\sum_{i=1}^n\varphi(i) \approx \frac {3N^2}{\pi ^2} Fn=1+∑i=1nφ(i)≈π23N2
本原勾股数(毕达哥拉斯三元组)
定义:三元组
(
a
,
b
,
c
)
(a,b,c)
(a,b,c) ,满足
a
2
+
b
2
=
c
2
a^2+b^2=c^2
a2+b2=c2,并且a、b、c互质
性质
- a和b为奇偶性不同,c为奇数
-
a
2
=
c
2
−
b
2
=
(
c
+
b
)
(
c
−
b
)
a^2=c^2-b^2=(c+b)(c-b)
a2=c2−b2=(c+b)(c−b),满足
c
+
b
c+b
c+b和
c
−
b
c-b
c−b互质,且
c
+
b
c+b
c+b和
c
−
b
c-b
c−b都是平方数,设
c
+
b
=
s
2
,
c
−
b
=
t
2
c+b=s^2,c-b=t^2
c+b=s2,c−b=t2,则
a
=
s
t
,
b
=
s
2
−
t
2
2
,
c
=
s
2
+
t
2
2
a=st,b=\frac {s^2-t^2}{2},c=\frac {s^2+t^2}{2}
a=st,b=2s2−t2,c=2s2+t2
根据性质2,可以通过枚举两个互质的奇数 s 、 t s、t s、t 构造本原勾股数 - 另一种构造方式:三元组表示为 ( 2 m n , m 2 − n 2 , m 2 + n 2 ) (2mn,m^2-n^2,m^2+n^2) (2mn,m2−n2,m2+n2),m与n互质,且奇偶性不同(两个互质的奇偶性不同的数)
法里数列习题
https://blog.csdn.net/sxh759151483/article/details/82984847
本原勾股数习题
Pythagoras HDU - 6211
题意:给出 2 k 2^k 2k 个数,且 x < y < z < 1 e 9 x<y<z<1e9 x<y<z<1e9 满足本原勾股数,求 ∑ a y m o d 2 k \sum a_{y\ mod\ 2^k} ∑ay mod 2k
解法一:法里数列+本原勾股数
分析:
- 法里数列可以满足互质的条件,然后再判断一下分子分母是否奇偶性不同就可以了。本地上跑栈会爆炸,oj上不会
- 因为k最大为17,所以在预处理的时候可以模 2 17 2^{17} 217,计算一下同余的个数,同余的数的贡献是一样的
#include <iostream>
#include <algorithm>
#define ll long long
using namespace std;
const int maxn=1e9,INF=0x3f3f3f3f;
const int mod=(1<<17)-1;
int T,a[mod+10],b[mod+10];
void solve(int l1,int r1,int l2,int r2)
{
int ml=l1+l2,mr=r1+r2;
if(1ll*ml*ml+1ll*mr*mr>maxn)
return;
if(mr-ml&1)
b[max(2ll*ml*mr,1ll*mr*mr-1ll*ml*ml)&mod]++;
solve(l1,r1,ml,mr);
solve(ml,mr,l2,r2);
}
int main()
{
solve(0,1,1,1);
scanf("%d",&T);
while(T--)
{
int k;
scanf("%d",&k);
k=(1<<k)-1;
for(int i=0;i<=k;++i)
scanf("%d",&a[i]);
ll ans=0;
for(int i=0;i<=mod;++i)
ans+=(ll)a[i&k]*b[i];
printf("%lld\n",ans);
}
return 0;
}
https://blog.csdn.net/codeswarrior/article/details/82703234
解法二:还是利用性质3来构造本原勾股数,但是通过互质判断的方法,枚举
i
i
i 从
1
1
1~
n
\sqrt n
n ,再枚举
j
j
j 从
1
1
1 ~
i
−
1
i-1
i−1
技巧:
1、互质判断的方法是:j 与 i 所有的质因子都不整除
2、计算a mod 2^n可以 用位运算:a&((1<<n)-1)
#include <iostream>
#include <algorithm>
#define ll long long
using namespace std;
const int maxn=1e5+5,INF=0x3f3f3f3f;
const int mod=(1<<17)-1;
const int N=1e9;
int T;
ll a[mod+10],b[mod+10];
void init()
{
for(int i=1;i*i<=N;++i)
{
int a=i,cnt=0,p[20];
for(int j=2;j*j<=a;++j)
{
if(a%j==0)
{
p[++cnt]=j;
while(a%j==0)
a/=j;
}
}
if(a>1)
p[++cnt]=a;
int c=i*i;
for(int j=1;j<i;++j)
{
c+=j+j-1;
if(c>N)
break;
if(i-j&1)
{
int k;
for(k=1;k<=cnt;++k)
if(j%p[k]==0)
break;
if(k>cnt)
{
int tmp=max(2*i*j,i*i-j*j);
b[tmp&mod]++;
}
}
}
}
}
int main()
{
init();
scanf("%d",&T);
while(T--)
{
int k;
scanf("%d",&k);
for(int i=0;i<(1<<k);++i)
scanf("%d",&a[i]);
int p=(1<<k)-1;
ll ans=0;
for(int i=0;i<=mod;++i)
ans+=(ll)a[i&p]*b[i];
printf("%lld\n",ans);
}
return 0;
}
Fermat vs. Pythagoras POJ - 1305
题意:在满足a,b,c<=n的情况下,求本原勾股数组的组数,以及剩下的不是勾股数的数的数量
思路:利用性质2和3都行,这里利用性质2,用两个互质的奇数来构造本原勾股数组
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#define ll long long
using namespace std;
const int maxn=1e6+5,INF=0x3f3f3f3f;
int n;
bool visit[maxn];
int main()
{
while(~scanf("%d",&n))
{
memset(visit,0,sizeof(visit));
int ans1=0;
for(int s=3;s<=n;s+=2)
{
for(int t=1;t<s;t+=2)
{
if(__gcd(s,t)==1)
{
ll a=s*t,b=(s*s-t*t)/2,c=(s*s+t*t)/2;
if(c>n)
continue;
ans1++;
int i=1;
while(1ll*c*i<=n)
{
visit[a*i]=visit[b*i]=visit[c*i]=true;
i++;
}
}
}
}
int ans2=0;
for(int i=1;i<=n;++i)
if(!visit[i])
ans2++;
printf("%d %d\n",ans1,ans2);
}
return 0;
}
P2508 [HAOI2008]圆上的整点
题意:求一个给定的圆
x
2
+
y
2
=
r
2
x^2+y^2=r^2
x2+y2=r2,给定一个
r
r
r,在圆周上有多少个点的坐标是整数
思路:一直以为是求本原勾股数,以为s、t要是两个奇数才行,后来才发现小数也行,在圆上的点是整数就行
x
2
+
y
2
=
r
2
x^2+y^2=r^2
x2+y2=r2 得到
x
2
=
r
2
−
y
2
=
(
r
+
y
)
(
r
−
y
)
x^2=r^2-y^2=(r+y)(r-y)
x2=r2−y2=(r+y)(r−y)设
d
=
g
c
d
(
r
+
y
,
r
−
y
)
d=gcd(r+y,r-y)
d=gcd(r+y,r−y)首先=(r+y)(r-y)是平方数,且
r
+
y
d
\frac {r+y}d
dr+y和
r
−
y
d
\frac {r-y}d
dr−y互质,也为平方数,设
s
2
=
r
+
y
d
s^2=\frac {r+y}d
s2=dr+y,
t
2
=
r
−
y
d
t^2=\frac {r-y}d
t2=dr−y,因此
s
2
+
t
2
=
2
r
d
s^2+t^2=\frac {2r}d
s2+t2=d2r
总结一下:我们只需找两个不等的互质的数
s
、
t
s、t
s、t满足
s
2
+
t
2
=
2
r
d
s^2+t^2=\frac {2r}d
s2+t2=d2r即可
做法:枚举2r的因子,然后把这个因子作为上限,枚举s、t,统计答案。并且s只需要枚举到
2
r
2
d
\frac {2r}{2d}
2d2r 就可以了,在继续枚举s、t就重复了
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>
#define ll long long
using namespace std;
const int maxn=1e5+5,INF=0x3f3f3f3f;
const int mod=1e9+7;
ll r;
ll gcd(ll a,ll b)
{
return b?gcd(b,a%b):a;
}
int check(ll d)
{
ll ans=0;
for(ll s=1;s*s<=2*r/d;s++)
{
int t=sqrt(2*r/d-s*s);
if(gcd(s,t)==1&&s*s+t*t==2*r/d)
{
ll x=(s*s-t*t)/2*d;
ll y=s*t*d;
if(x>0&&y>0&&x*x+y*y==r*r)
ans+=2;
}
}
return ans;
}
int main()
{
scanf("%lld",&r);
ll ans=0;
for(ll d=1;d*d<=2*r;d++)
{
if(2*r%d==0)
{
ans+=check(d);
if(d*d!=2*r)
ans+=check(2*r/d);
}
}
printf("%lld\n",ans*4+4);
return 0;
}
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#define ll long long
using namespace std;
ll gcd(ll a,ll b)
{
return b?gcd(b,a%b):a;
}
ll r;
int check(int d)
{
int ans=0;
for(int s=1;s*s<=r/d;++s)
{
double t1=sqrt(2.0*r/d-s*s);
int t=t1;
if(t==t1&&gcd(s,t)==1&&s!=t)
ans++;
}
return ans;
}
int main()
{
ll ans=0;
scanf("%lld",&r);
for(ll d=1;d*d<=2*r;++d)
{
if(2*r%d==0)
{
ans+=check(d);
if(d*d!=2*r)
ans+=check(2*r/d);
}
}
printf("%lld\n",ans*4+4);
return 0;
}