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+1≡0(modb+1) a + 1 ≡ b + 1 ( m o d b + 1 ) a+1\equiv b+1\pmod{b+1} a+1≡b+1(modb+1) a − b ≡ 0 ( m o d b + 1 ) a-b\equiv0\pmod{b+1} a−b≡0(modb+1) ∵ a b = p ∴ a = b ∗ p \because\dfrac ab=p\quad\therefore a=b*p ∵ba=p∴a=b∗p b ∗ ( p − 1 ) ≡ 0 ( m o d b + 1 ) b*(p-1)\equiv0\pmod{b+1} b∗(p−1)≡0(modb+1) b ∗ ( p − 1 ) ∣ ( b + 1 ) b*(p-1)|(b+1) b∗(p−1)∣(b+1) ∵ b和b+1互质 ∴ ( p − 1 ) ∣ ( b + 1 ) \because\text{b和b+1互质}\quad\therefore(p-1)|(b+1) ∵b和b+1互质∴(p−1)∣(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∗(p−1)≡0(modb+2) b ∗ ( p − 1 ) ∣ ( b + 2 ) b*(p-1)|(b+2) b∗(p−1)∣(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} {(p−1)∣(b+2)b为奇数2∗(p−1)∣(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} {(p−1)∣(b+1)(b+2)b为奇数2∗(p−1)∣(b+1)(b+2)b为偶数
当 b b b 为奇数时,设 p − 1 = k ∗ ( b + 1 ) ∗ ( b + 2 ) p-1=k*(b+1)*(b+2) p−1=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}≤3p−1<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) p−1=k∗(b+1)∗(b+2)⇔2∗(p−1)=(2∗k)∗(b+1)∗(b+2)⇒2∗(p−1)=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∗(p−1)=k∗(b+1)∗(b+2) 只是个必要条件,我们得到的 b b b 有一部分是不满足条件的(毕竟凭空多分给了 p − 1 p-1 p−1 一个因数 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;
}