佩尔方程
解决问题:
一般解决中解的问题。在大多数的时候都不会给你这个式子,要有你自己来推成这个形式。
一定要注意当n为平方数的时候无解
解决方法:
一般都要你推出最小解(可以用程序跑出来第一个),计为(x[1],y[1])。然后再用递推公式来求解
佩尔方程求解:
x^2 - n*y^2 = 1
x[i+1] = x[1]*x[i] + n* y[1]*y[i]
y[i+1] = x[1]*y[i] + y[1]*x[i]
例题1:
找出最大的整数n(1 <= n <= N)和整数x以使它们满足
输入项输入包含几个测试用例。每个测试用例包含一个整数N,1 <= N <= 10 ^ 18。输入以N = 0结尾。输出量在每种情况的一行中,输出您找到的两个整数n和x。样本输入
1 2 0
样本输出
1 1 1 1
#include<iostream> #include<algorithm> #include<vector> using namespace std; typedef long long ll; typedef __int128 hll; const int maxn=1e4+100; vector<ll> v; ll ans[maxn]; ll n; //x^2==(n+1)*(2*n+1)/6 //(4+3)^2-48x^2=1 //先找到一个x,n //然后再用跌代公式做 //x^2 - n*y^2 = 1 //x[i+1] = x[1]*x[i] + n* y[1]*y[i] //y[i+1] = x[1]*y[i] + y[1]*x[i] int main(){ hll x=7,y=1; while((x-3)/4<=1e18){ if((x-3)%4==0){ ans[v.size()]=y; v.push_back((x-3)/4); } hll x1=x,y1=y; x=7*x1+48*y1; y=7*y1+x1; } while(scanf("%lld",&n)&&n){ int p=upper_bound(v.begin(),v.end(),n)-v.begin()-1; printf("%lld %lld ",v[p],ans[p]); } }
例二:
传送门
如果三角形满足边长为连续的整数t-1,t,t + 1,并且面积为整数,则为Heron三角形。现在,对于给定的n,您需要找到与最小t
大于或等于n的苍鹭三角形 。
大于或等于n的苍鹭三角形 。
输入项输入包含多个测试用例。多重输入的第一行是整数T(1≤T≤30000),后跟T行。每行包含一个整数N(1≤N≤10 ^ 30)。
输出量对于每个测试用例,输出一行中最小的t。如果所需的苍鹭三角形不存在,则输出-1。样本输入
4 1 2 3 4
样本输出
4 4 4 4
题意
给定一个整数 N(1≤N≤1^30),求最小的整数 t,要求 t≥N,使得边长为 t−1,t,t+1 的三角形面积为整数。
#include<iostream> #include<algorithm> #include<vector> using namespace std; typedef long long ll; typedef __int128 hll; const int maxn=1e3+100; __int128 xx[maxn],yy[maxn]; //x^2-3y^2=1 . /* x^2 - n*y^2 = 1 x[i+1] = x[1]*x[i] + n* y[1]*y[i] y[i+1] = x[1]*y[i] + y[1]*x[i] */ void read(__int128 &x) {//__int128的板子 x = 0; char ch; int flag = 1; while (ch = getchar()) { if (ch == '-') flag = -1; if (ch >= '0' && ch <= '9') break; } x = ch-'0'; while ((ch = getchar()) >= '0' && ch <= '9') { x = x*10 + ch-'0'; } x *= flag; } void out(__int128 x) { if (x < 0) { x = -x; putchar('-'); } if (x >= 10) out(x / 10); putchar(x % 10 +'0'); } void inint(){ xx[1]=2,yy[1]=1; for(int i=2;i<=100;i++){ xx[i]=xx[i-1]*2+yy[i-1]*3; yy[i]=yy[i-1]*2+xx[i-1]; } } int main(){ int t; cin>>t; inint(); while(t--){ __int128 n; read(n); for(int i=1;i<=100;i++){ if(xx[i]*2>=n){ out(xx[i]*2); cout<<endl; break; } } } return 0; }
根据海伦公式:S=p(p−a)(p−b)(p−c)−−−−−−−−−−−−−−−−−√,p=a+b+c2.
代入,令 t2=x,化简得 S2=3x2(x2−1).
题目要求 S 为整数,则 (x2−1) 一定是3乘以一个平方数,
即 x2−1=3y2,即 x2−3y2=1.
易知最小解为(2, 1),用递推式求出其他解即可。
由于题目 N 的范围较大,到 1e30,可以使用 int128(1e38),本地测试1e38内,只有67个解。