题目大意:首先给出一个数t表示样例的数目,下面的t行,每行有一个数n,要求我们求出满足上面式子的数对(x,y)的数量,其中1<=x<=y<=n。
题目解析:通过打表我们可以发现,当y=x^3时,以上式子始终满足。打表结果如下:
x^2 + y^2 = k(xy + 1) // k是正整数
⇒ y^2 - kxy - k + x^2 = 0 // (1)
可以将x看成一个固定的值。
由韦达定理有 y1 + y2 = kx
对于一对满足条件的(x, y),有一对(x, kx - y)也满足条件。
所以(y, x)也满足条件,此时y是固定的,有(y, ky - x)条件。
对于上面打表找出的特例:(x,x^3)带入(1)式,得到 k = x^2。(以上推导来自一篇大佬博客:(144条消息) 2021牛客暑期多校训练营3-E(Math)_sweetheart7-7的博客-CSDN博客)
所有就有了:
(x, x^3)
(x^3, x^5 - x)……
这样无线循环下去,直到当前数对的y超出给定范围。
在写代码的时候,自己在实现上出现了错误。
先上错误代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N =2e6+10;
long long ans[7001000];
int main()
{
int cnt=0;
ans[cnt++]=1;
for(long long i=2;i<=1e6;i++)
{
long long x=i,y=i*i*i,k=i*i;
while(y<=(1e18+x)/k)//k*y-x<=1e18
{
ans[cnt++]=y;
long long temp=k*y-x;
x=y;
y=temp;//y>(1e18+x)/k && y valid
}
}
sort(ans,ans+cnt);
for(int i=1000;i<=10100;i++){
cout<<ans[i]<<endl;
}
int t ;
cin>>t;
while(t--)
{
long long n;
cin>>n;
cout<<upper_bound(ans,ans+cnt,n)-ans<<endl;
}
return 0;
}
下面是正确代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
long long ans[7001000];//这里尽量开大一点,不然很容易就会RE
int main()
{
int cnt=0;
ans[cnt++]=1;
for(long long i=2;i<=1e6;i++)
{
long long x=i,y=i*i*i,k=i*i;
ans[cnt++]=y;
while(y<=(1e18+x)/k)
{
long long temp=k*y-x;
x=y;
y=temp;
ans[cnt++]=y;
}
}
sort(ans,ans+cnt);
int t ;
cin>>t;
while(t--)
{
long long n;
cin>>n;
cout<<upper_bound(ans,ans+cnt,n)-ans<<endl;
}
return 0;
}
下面来比较一下这两份代码的不同之处:
错误:
正确:
这里考验的就是我们对while循环中判断条件的理解了,这里判断条件是怎么来的呢?它是根据式子:k*y-x<=1e18变形得来的,也就是说此时我们是把上一个状态的y当作当前状态的x来看,如果该条件满足,我们就应该将当前状态的y'=k*y-x加入数组中,而错误代码的意思是,拿当前状态的y'(上一个状态的y),判断下一个状态的y',如果满足条件就将当前状态的y'加入数组之中,这显然是不对的,因为下一个状态不合法,但是当前状态是合法的,如果没有加进去一定会导致答案出错。这里纠结调了好久就没有发现这个错误,还好队友给力帮我找到了这处bug。