题目内容
T
T
T 组数据,
每组数据给定一个整数
x
x
x ,构造一个下标从
1
1
1 开始的,长度为
1
0
100
10^{100}
10100 的数组
a
a
a 。
满足
a
1
=
x
a_1=x
a1=x ,
a
i
×
a
i
≤
a
i
−
1
(
2
≤
i
≤
1
0
100
)
a_i\times a_i\leq a_{i-1}(2\leq i\leq 10^{100})
ai×ai≤ai−1(2≤i≤10100)
问可以构造输出多少种不同的数组 a a a 。
数据范围
1 ≤ x ≤ 9 × 1 0 18 1\leq x\leq 9\times 10^{18} 1≤x≤9×1018
题解
一个关键的点在于,后一个数 a i a_i ai 至多是前一个数 a i − 1 a_{i-1} ai−1 的平方根,即 a i ≤ a i − 1 a_i\leq \sqrt{a_{i-1}} ai≤ai−1
以下用 x \sqrt{x} x 表示数 x x x 开平方根后下取整
所以当每个
a
i
=
a
i
−
1
a_i=\sqrt{a_{i-1}}
ai=ai−1
考虑极端情况,
a
1
=
9
×
1
0
18
a_1=9\times 10^{18}
a1=9×1018
a
2
=
3
×
1
0
9
a_2=3\times 10^9
a2=3×109
a
3
=
54772
a_3=54772
a3=54772
a
4
=
233
a_4=233
a4=233
a
5
=
15
a_5=15
a5=15
a
6
=
3
a_6=3
a6=3
a
7
=
1
a_7=1
a7=1
故至多 6 6 6 次开根, a i a_i ai 就必须为 1 1 1 了。
定义 f i , j f_{i,j} fi,j 表示数组长度为 i i i ,第 i i i 个数为 j j j 的 方案数
可以知道的是,
f
2
,
j
=
1
f_{2,j}=1
f2,j=1 ,其中
j
2
≤
x
j^2\leq x
j2≤x
那么对于,
f
3
,
k
f_{3,k}
f3,k 来说,
f
3
,
k
=
∑
j
=
k
2
x
f
2
,
j
=
x
−
k
2
+
1
f_{3,k}=\sum\limits_{j={k^2}}^{\sqrt{x}}f_{2,j}=\sqrt{x}-k^2+1
f3,k=j=k2∑xf2,j=x−k2+1
对于 f 4 , f 5 , f 6 , f 7 f_4,f_5,f_6,f_7 f4,f5,f6,f7 来说,取值范围太小,可以直接暴力。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 55000;
ll dp[N];
ll ndp[N];
void solve() {
ll a;
cin >> a;
/*
dp[0][a] = 1;
b = sqrtl(a)
dp[1][b] = 1;
dp[1][b-1] = 1
dp[1][b-2] = 1
dp[1][b-3] = 1
...
dp[1][1] = 1
c = sqrtl(b)
dp[2][c] = dp[1][c^2]+dp[1][c^2+1]+...+dp[1][b]
dp[2][c-1] = dp[1][(c-1)^2]+dp[1][(c-1)^2+1]+...dp[1][c]
*/
ll b = sqrtl(a);
ll c = sqrtl(b);
// dp[2]
dp[c + 1] = 0;
for (ll i = c; i >= 1; --i) {
dp[i] = b - i * i + 1;
dp[i] += dp[i + 1];
}
// dp[3...]
while (c > 1) {
ll d = sqrtl(c);
ndp[d + 1] = 0;
for (ll i = d; i >= 1; --i) {
ndp[i] = dp[i * i];
ndp[i] += ndp[i + 1];
}
for (int i = 1; i <= d; ++i) dp[i] = ndp[i];
c = d;
}
cout << dp[1] << "\n";
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T = 1;
cin >> T;
while (T--) {
solve();
}
return 0;
}