长治市网站建设_网站建设公司_支付系统_seo优化
2026/1/20 14:33:48 网站建设 项目流程

题意简析

给定序列 \(a\),求出选择的使得相邻的两数 \(\gcd \ge L\) 的最长的子序列的长度。

思路解析

一拿到题目,我们就看见有求最长的子序列,我们想到了 LIS,可惜这里有条件才能转移。

\(dp_i\) 为 LIS 长度,状态转移方程为:

\[ dp_i = 1 + \max dp_j \]

这样子做是 \(O(n^2)\) 的,显然不能过。


我们在取 \(\max\) 时,其实有更多地方重复计算,还是可以优化的。

注意到 \(\max\) 的不断操作下,数值是单调不降的,那么我们可以维护 \(fac_d\) 为被 \(d\) 整除的数的 \(dp\) 最大值。

枚举每一个 \(a_i\) 的因数,然后更新 \(fac_d\),当前的 \(dp_i\) 就是 \(fac_d\) 最大值加一。然后,用 \(dp[i]\) 更新满足条件的 \(fac_d\) 即可。

总复杂度 \(O(n \sqrt{\max a_i})\),可以通过此题。

代码实现

#include <bits/stdc++.h>
using namespace std;
const int V = 1e6 + 5;
int n, l, ans, dp[V], mx, res;
int main() {ios::sync_with_stdio(false);cin.tie(nullptr);cin >> n >> l;for (int i = 0, x; i < n; i++) {vector<int> fac;mx = 0;cin >> x;for (int d = 1; d * d <= x; d++) {if (!(x % d)) {if (d >= l) {fac.push_back(d);}if (x / d != d && x / d >= l) {fac.push_back(x / d);}}}for (int j = 0; j < fac.size(); j++) {int d = fac[j];mx = max(mx, dp[d]);}res = mx + 1;for (int j = 0; j < fac.size(); j++) {int d = fac[j];dp[d] = max(dp[d], res);}ans = max(ans, res);}cout << ans;return 0;
}

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询