91
这个题的扩展满足 \(N \le 2500\),枚举每个点的位置去计算太慢,我们能否通过枚举一条线来计算答案?
考虑枚举一条斜率为 \(\frac{y}{x}\) 的一条直线,这条直线在至少可以在范围内交出 \((x, \, y)\) 这个点,我们以 \((0, \, 0), \, (x, \, y)\) 为一条直角边,显然只有过 \((x, \, y)\) 做这条直线的垂线所过的整数点是合法的,我们只考虑一侧,因为另一侧是等价的。
设 \(d = \gcd(x, \, y)\) 也就是说这样的点应该横坐标每增加 \(\frac{y}{d}\) 纵坐标就减少 \(\frac{x}{d}\),那么合法点的个数为
\[c = \min\left(\left\lfloor\frac{N - x}{\frac{y}{d}}\right\rfloor, \, \left\lfloor\frac{y}{\frac{x}{d}}\right\rfloor\right)
\]
化简可得
\[c = \min\left(\left\lfloor\frac{(N - x)d}{y}\right\rfloor, \, \left\lfloor\frac{yd}{x}\right\rfloor\right)
\]
对称相当于乘二,然后加上与 \(xOy\) 坐标轴平行的直角三角形个数 \(3N^2\) 即可。
// cpp
#include<bits/stdc++.h>
using namespace std;int main() {int ans = 0, N = 50;for (int x = 1; x <= N; x ++ ) {for (int y = 1; y <= N; y ++ ) {int d = __gcd(x, y);ans += min((N - x) * d / y, y * d / x);}}cout << ans * 2 + N * N * 3;return 0;
}
92
我们把相互转换的数链接一条边,利用并查集,我们可以把数分为属于 \(1\) 或属于 \(89\) 的,如此可以计算。
// cpp
#include<bits/stdc++.h>
using namespace std;
const int N = 1e7 + 5;
int n = 1e7, p[N];int find(int x) {if (p[x] != x) p[x] = find(p[x]);return p[x];
}int main() {for (int i = 1; i <= n; i ++ ) p[i] = i;for (int i = 1; i <= n; i ++ ) {int t = 0, x = i;while (x) t += (x % 10) * (x % 10), x /= 10;p[find(i)] = find(t);}int ans = 0;for (int i = 1; i <= n; i ++ ) {if (find(i) == find(89)) ans ++ ;}cout << ans;return 0;
}