E.Math
题面:
题目大意:
给定
n
n
n的情况下,问你在
1
≤
x
≤
y
≤
n
1≤x≤y≤n
1≤x≤y≤n的范围内,能找到多少组数对
(
x
,
y
)
(x,y)
(x,y),使得
x
2
+
y
2
x^2+y^2
x2+y2除以
x
∗
y
+
1
x*y+1
x∗y+1是一个整数。
输出数量。
题目思路:
先打个表找规律。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main() {
int i=10000;
ll cnt = 0;
cout << i << ":" << endl;
for (int m = 1; m <= i; m++)
for (int n = m; n <= i; n++) {
if ((m * m + n * n) % (m * n + 1) == 0) {
cnt++;
cout << cnt << ":" << m << " " << n << endl;
}
}
cout << cnt << endl;
cout << endl;
}
关于这组数
是某年的IMO题,关键点是韦达跳跃。
打表结果如下:
x与y为三次方倍关系的很常见,再把不正常的筛选出来看看:
8 30
30 112
27 240
112 418
64 1020
418 1560
240 2133
125 3120
1560 5822
216 7770
343 16800
2133 18957
里面出现了一些首尾相关的部分:8->30->112->418->1560->5822
;27->240->2133->18957
;64->1020->16256
125->3120
…
发现:
- 都是 w 3 w^3 w3开头
- a i + 1 = a i ∗ ( w 2 ) − a i − 1 a_i+_1=a_i*(w^2)-a_i-_1 ai+1=ai∗(w2)−ai−1
30
=
8
∗
2
2
−
2
30=8*2^2-2
30=8∗22−2
112
=
30
∗
2
2
−
8
112=30*2^2-8
112=30∗22−8
由这个规律开始打表做。
代码:
#include <bits/stdc++.h>
#define ll unsigned long long
using namespace std;
vector<ll> st;
int main() {
st.push_back(1);
for (ll i = 2; i <= (1e6); i++) {
ll now = i * i * i, pre = i;
while (now <= (1e18)) {
st.push_back(now);
if (now > (1e18 + i) / (i * i)) break;
//小 心 爆 炸
ll tp = i * i * now - pre;
if (tp > 1e18)break;
//小 心 爆 炸
pre = now;
now = tp;
}
}
sort(st.begin(), st.end());
//for(int i=0;i<=10;i++)cout<<st[i]<<'\n';
ll t;
cin >> t;
while (t--) {
ll n;
cin >> n;
ll p = lower_bound(st.begin(), st.end(), n + 1) - st.begin();
cout << p << '\n';
}
}