题解:P17717 [LAOI Round 21] 拼积木 / block
来一个比较完整详细的题解吧。
正解
首先,假如
因此我们定义一个极小的区间
假设我们现在已经求出了对于所有
也就是统计上一个极小区间对于
那么如何求出所有极小区间呢?暴力即可!为什么这是对的?不妨分类讨论。
这里单调递减,所以我们分类讨论。首先是长度
有总时间复杂度
代码
#include <bits/stdc++.h>
#define rep(i, l, r) for(int i = (l); i <= (r); i ++ )
#define per(i, l, r) for(int i = (l); i >= (r); i -- )
#define frein(s) freopen(s, "r", stdin)
#define freout(s) freopen(s, "w", stdout)
#define int long long
#define endl '\n'
using namespace std;
const int N = 1e6 + 5;
int T, n, a[N], nxt[N], dp[N];
signed main() {
ios :: sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> T;
while(T -- ) {
cin >> n;
rep(i, 1, n) cin >> a[i];
rep(i, 0, n) nxt[i] = dp[i] = 0;
rep(i, 1, n) {
int t = a[i];
if(a[i] == 1) {
nxt[i] = i;
continue;;
}
rep(j, i + 1, n) {
t = max(t, a[j]) / min(t, a[j]);
if(t == 1) {
nxt[i] = j;
break;
}
}
}
int ans = 0;
rep(i, 1, n) {
dp[nxt[i]] += dp[i - 1] + 1;
ans += dp[i];
}
cout << ans << endl;
}
return 0;
}
部分分解法
\sum n\leq 5\times 10^2
枚举每一个区间,从左到右扫描,依次判断是否为合法区间。时间复杂度
\sum n\leq 5\times 10^3
对上一个做法的略微优化。我们枚举左端点,然后从左向右扫描右端点,假如遇到
相较于上一个做法避免了计算重复的前缀,因此时间复杂度优化到了