法里数列和本原勾股数

法里数列

  1. 性质1:连续三项为 b a 、 b + d a + c 、 d c \frac ba 、\frac{b+d}{a+c}、 \frac dc aba+cb+dcd,且分子分母满足是互质的(真分数)
  2. 性质2:指定一个常数N,它的法里数列的项数为 φ ( N ) \varphi(N) φ(N),因此可以得到前缀和是: 2 + φ ( 2 ) + φ ( 3 ) + ⋯ + φ ( N ) 2+\varphi(2)+\varphi(3)+\dots+\varphi(N) 2+φ(2)+φ(3)++φ(N)
  3. 数列的中项永远是 1 2 \frac 12 21
  4. 任意两项 b a 和 d c \frac ba和\frac dc abcd 满足 a b s ( a d − b c ) = 1 abs(ad-bc)=1 abs(adbc)=1
  5. 项数公式: 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互质
性质

  1. a和b为奇偶性不同,c为奇数
  2. a 2 = c 2 − b 2 = ( c + b ) ( c − b ) a^2=c^2-b^2=(c+b)(c-b) a2=c2b2=(c+b)(cb),满足 c + b c+b c+b c − b c-b cb互质,且 c + b c+b c+b c − b c-b cb都是平方数,设 c + b = s 2 , c − b = t 2 c+b=s^2,c-b=t^2 c+b=s2,cb=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=2s2t2,c=2s2+t2
    根据性质2,可以通过枚举两个互质的奇数 s 、 t s、t st 构造本原勾股数
  3. 另一种构造方式:三元组表示为 ( 2 m n , m 2 − n 2 , m 2 + n 2 ) (2mn,m^2-n^2,m^2+n^2) (2mn,m2n2,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

解法一法里数列+本原勾股数
分析:

  1. 法里数列可以满足互质的条件,然后再判断一下分子分母是否奇偶性不同就可以了。本地上跑栈会爆炸,oj上不会
  2. 因为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 i1
技巧:
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=r2y2=(r+y)(ry) d = g c d ( r + y , r − y ) d=gcd(r+y,r-y) d=gcd(r+y,ry)首先=(r+y)(r-y)是平方数,且 r + y d \frac {r+y}d dr+y r − y d \frac {r-y}d dry互质,也为平方数,设 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=dry,因此 s 2 + t 2 = 2 r d s^2+t^2=\frac {2r}d s2+t2=d2r
总结一下:我们只需找两个不等的互质的数 s 、 t s、t st满足 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值