Continued Fractions(数论,开方法)

这篇文章介绍了如何解决ICPC2023-2024SwissSubregional比赛中的连续分数题目,通过分析给定正整数p,寻找满足特定条件的(a,b)整数对。关键思路是利用整除性质和互质性来确定b和b+1、b和b+2之间的公约数关系。
摘要由CSDN通过智能技术生成

2023-2024 ICPC, Swiss Subregional

C. Continued Fractions

题目链接


Continued Fractions

题意:

给定正整数 p p p,求使得 a b = p \dfrac ab=p ba=p,且 a + 1 b + 1 , a + 2 b + 2 \dfrac{a+1}{b+1},\dfrac{a+2}{b+2} b+1a+1,b+2a+2 为整数的 ( a , b ) (a,b) (a,b) 对数。

思路:

官方题解

讲讲我的证明过程。因为 a + 1 b + 1 \dfrac{a+1}{b+1} b+1a+1 为整数,因此: ( a + 1 ) ∣ ( b + 1 ) (a+1)|(b+1) (a+1)(b+1) a + 1 ≡ 0 ( m o d b + 1 ) a+1\equiv0\pmod{b+1} a+10(modb+1) a + 1 ≡ b + 1 ( m o d b + 1 ) a+1\equiv b+1\pmod{b+1} a+1b+1(modb+1) a − b ≡ 0 ( m o d b + 1 ) a-b\equiv0\pmod{b+1} ab0(modb+1) ∵ a b = p ∴ a = b ∗ p \because\dfrac ab=p\quad\therefore a=b*p ba=pa=bp b ∗ ( p − 1 ) ≡ 0 ( m o d b + 1 ) b*(p-1)\equiv0\pmod{b+1} b(p1)0(modb+1) b ∗ ( p − 1 ) ∣ ( b + 1 ) b*(p-1)|(b+1) b(p1)(b+1) ∵ b和b+1互质 ∴ ( p − 1 ) ∣ ( b + 1 ) \because\text{b和b+1互质}\quad\therefore(p-1)|(b+1) bb+1互质(p1)(b+1)

同理,可以推 a + 1 b + 1 \dfrac{a+1}{b+1} b+1a+1 为整数的情况,得到: b ∗ ( p − 1 ) ≡ 0 ( m o d b + 2 ) b*(p-1)\equiv0\pmod{b+2} b(p1)0(modb+2) b ∗ ( p − 1 ) ∣ ( b + 2 ) b*(p-1)|(b+2) b(p1)(b+2)这时 b b b b + 2 b+2 b+2 不一定互质,但是只有可能有一个公因数 2 2 2(因为同时提公因数 2 2 2 后, b 2 \dfrac b2 2b b 2 + 1 \dfrac b2+1 2b+1 是互质的),并且当且仅当 b b b 为偶数时,有公因数 2 2 2。因此得到 { ( p − 1 ) ∣ ( b + 2 ) b 为奇数 2 ∗ ( p − 1 ) ∣ ( b + 2 ) b 为偶数 \begin{equation} \left\{ \begin{aligned} (p-1)|(b+2) \quad b\text{为奇数}\\ 2*(p-1)|(b+2) \quad b\text{为偶数}\\ \end{aligned} \right. \end{equation} {(p1)(b+2)b为奇数2(p1)(b+2)b为偶数

因为 b + 1 b+1 b+1 b + 2 b+2 b+2 也是互质的。因此得到: { ( p − 1 ) ∣ ( b + 1 ) ( b + 2 ) b 为奇数 2 ∗ ( p − 1 ) ∣ ( b + 1 ) ( b + 2 ) b 为偶数 \begin{equation} \left\{ \begin{aligned} (p-1)|(b+1)(b+2) \quad b\text{为奇数}\\ 2*(p-1)|(b+1)(b+2) \quad b\text{为偶数}\\ \end{aligned} \right. \end{equation} {(p1)(b+1)(b+2)b为奇数2(p1)(b+1)(b+2)b为偶数

b b b 为奇数时,设 p − 1 = k ∗ ( b + 1 ) ∗ ( b + 2 ) p-1=k*(b+1)*(b+2) p1=k(b+1)(b+2) ,因为 m i n { k , b + 1 , b + 2 } = m i n { k , b + 1 } ≤ p − 1 3 < 1 0 6 min\{k,b+1,b+2\}=min\{k,b+1\}\le\sqrt[3]{p-1}\lt10^6 min{k,b+1,b+2}=min{k,b+1}3p1 <106,所以我们枚举三个约数的最小值,并令 k , b + 1 k,b+1 k,b+1 等于这个值,看是否满足条件即可。

同理处理偶数。

code:

#include <iostream>
#include <cstdio>
#include <vector>
#include <set>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;

int T;
ll p,b;

ll g(ll y){
	ll l=1,r=1e9,mid;
	while(l<r){
		mid=(l+r+1)>>1;
		if((mid+1)*(mid+2)<=y)l=mid;
		else r=mid-1;
	}
	return ((l+1)*(l+2)==y)?l:-1;
}

int main(){
	cin>>T;
	while(T--){
		cin>>p;
		ll n=2*(p-1);
		set<ll> ans;
		
		for(ll d=1,t,b,k;d*d*d<=n;d++){
			k=d;
			if(n%k==0){
				t=n/k;
				b=g(t);
				if(~b && b+1>k){
					if((b&1)==0)ans.insert(b);
				}
			}
			
			b=d;
			if(n%((b+1)*(b+2))==0){
				k=n/(b+1)/(b+2);
				if(k>=b+1){
					if((b&1)==0)ans.insert(b);
				}
			}
		}
		
		n=p-1;
		for(ll d=1,t,b,k;d*d*d<=n;d++){
			k=d;
			if(n%k==0){
				t=n/k;
				b=g(t);
				if(~b && b+1>k){
					if((b&1)==1)ans.insert(b);
				}
			}
			
			b=d;
			if(n%((b+1)*(b+2))==0){
				k=n/(b+1)/(b+2);
				if(k>=b+1){
					if((b&1)==1)ans.insert(b);
				}
			}
		}
		
		cout<<ans.size()<<endl;
		for(auto b:ans)cout<<b<<" ";
		cout<<endl;
	}
	return 0;
}
/*

3
6402373705728001
121645100408832001
219060189739591201
287 293
*/

借鉴题解的做法,上面当 b b b 为奇数的时候 p − 1 = k ∗ ( b + 1 ) ∗ ( b + 2 ) ⇔ 2 ∗ ( p − 1 ) = ( 2 ∗ k ) ∗ ( b + 1 ) ∗ ( b + 2 ) ⇒ 2 ∗ ( p − 1 ) = k ∗ ( b + 1 ) ∗ ( b + 2 ) p-1=k*(b+1)*(b+2)\Leftrightarrow 2*(p-1)=(2*k)*(b+1)*(b+2)\Rightarrow 2*(p-1)=k*(b+1)*(b+2) p1=k(b+1)(b+2)2(p1)=(2k)(b+1)(b+2)2(p1)=k(b+1)(b+2),这就和 b b b 为偶数时的式子相同了,我们直接对这个式子来做即可。不过需要注意的是 2 ∗ ( p − 1 ) = k ∗ ( b + 1 ) ∗ ( b + 2 ) 2*(p-1)=k*(b+1)*(b+2) 2(p1)=k(b+1)(b+2) 只是个必要条件,我们得到的 b b b 有一部分是不满足条件的(毕竟凭空多分给了 p − 1 p-1 p1 一个因数 2 2 2)。所以最后需要重新验证一遍。

#include <iostream>
#include <cstdio>
#include <vector>
#include <set>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;

int T;
ll p,b;

ll g(ll y){
	ll l=1,r=1e9,mid;
	while(l<r){
		mid=(l+r+1)>>1;
		if((mid+1)*(mid+2)<=y)l=mid;
		else r=mid-1;
	}
	return ((l+1)*(l+2)==y)?l:-1;
}

int main(){
	cin>>T;
	while(T--){
		cin>>p;
		ll n=2*(p-1);
		set<ll> ans;
		
		for(ll d=1,t,b,k;d*d*d<=n;d++){
			k=d;
			if(n%k==0){
				t=n/k;
				b=g(t);
				if(~b && b+1>=k)ans.insert(b);
			}
			
			b=d;
			if(n%((b+1)*(b+2))==0){
				k=n/(b+1)/(b+2);
				if(k>=b+1)ans.insert(b);
			}
		}
		
		set<ll> t;
		for(auto b:ans){
			__int128 a=b;a*=p;
			if((a+1)%(b+1)==0 && (a+2)%(b+2)==0)
				t.insert(b);
		}
			
		cout<<t.size()<<endl;
		for(auto b:t)
			cout<<b<<" ";
		cout<<endl;
		
	}
	return 0;
}
  • 26
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值