题目
算法标签: 动态规划, 线性 d p dp dp, 位运算
思路
数据范围 n = 1 0 5 n = 10 ^ 5 n=105, 假设定义状态表示 f [ i ] f[i] f[i]表示以 i i i为结尾的最长的符合条件的子序列的长度, 那么需要枚举上一个位置 j j j, 观察 w [ i ] w[i] w[i] & w [ j ] w[j] w[j]的结果是否是 0 0 0如果是 0 0 0不能从该状态转移过来, 那么能够转移的状态就是 1 ∼ i − 1 1 \sim i- 1 1∼i−1当中符合条件的 j j j的 f [ j ] f[j] f[j]的最大值, 如果直接枚举时间复杂度是 O ( n 2 ) O(n ^ 2) O(n2)会超时, 需要进行优化
发现直接优化状态计算没办法优化, 考虑重新对集合进行划分, 定义状态表示 f [ i ] f[i] f[i]表示以第 i i i位为 1 1 1的所有子序列中长度最长的子序列, 考虑如何进行状态转移
每加入一个数字, 枚举所有位置 0 ∼ 31 0 \sim 31 0∼31, 检查每一位是否是 1 1 1, 如果是 1 1 1更新最大值, 然后得到最大后再更新回状态转移数组, 算法时间复杂度 O ( n log m ) O(n\log m) O(nlogm)可以通过
代码
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 1e5 + 10, M = 32;
int n, f[M];
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n;
int ans = 1;
for (int i = 1; i <= n; ++i) {
int val;
cin >> val;
int tmp = 1;
for (int k = 0; k < M; ++k) {
if (val >> k & 1) tmp = max(tmp, f[k] + 1);
}
for (int k = 0; k < M; ++k) {
if (val >> k & 1) f[k] = max(f[k], tmp);
}
ans = max(ans, tmp);
}
cout << ans << "\n";
return 0;
}

京公网安备 11010502036488号