arc207c - Combine to Make Non-decreasing

Problem

Problem Statement

You are given an integer sequence of length N , A = ( A 1 , A 2 , ⋯   , A N ) N, A = (A_1, A_2, \cdots, A_N) N,A=(A1,A2,⋯,AN). Snuke wants to make A A A a non-decreasing sequence.

He can perform the following operation zero or more times.

  • Choose two adjacent elements of A A A
  • Remove these two elements and insert the bitwise OR \text{OR} OR of these two values at the original position

Find the maximum possible value of the length of A A A when A A A becomes a non-decreasing sequence.

Constraints

  • 1 ≤ N ≤ 2 × 10 5 1 \le N \le 2 \times 10^5 1≤N≤2×105
  • 1 ≤ A i < 2 30 1 \le A_i < 2^{30} 1≤Ai<230
  • All input values are integers.

Translation

问题描述

给定一个长度为 N N N 的整数序列 A = ( A 1 , A 2 , ⋯   , A N ) A = (A_1, A_2, \cdots, A_N) A=(A1,A2,⋯,AN)。Snuke 想要将 A A A 变成一个非递减序列。

他可以执行以下操作零次或多次:

  • 选择 A A A 中两个相邻的元素
  • 移除这两个元素,并在原位置插入这两个值的按位或( OR \text{OR} OR)结果

请找出当 A A A 成为非递减序列时,序列 A A A 的最大可能长度。

限制条件

  • 1 ≤ N ≤ 2 × 10 5 1 \le N \le 2 \times 10^5 1≤N≤2×105
  • 1 ≤ A i < 2 30 1 \le A_i < 2^{30} 1≤Ai<230
  • 所有输入值均为整数。

Solutions

Approach 1

动态规划,RMQ,动态规划的状态设计优化。

首先,用 RMQ 维护区间按位或的结果,通过预处理 log ⁡ 2 ( n ) \log_2(n) log2(n) 的结果可以实现 O ( 1 ) O(1) O(1) 查询区间按位或。

先考虑最基础的可解 dp 方程,不难设计 d p i j = k dp_{ij} = k dpij=k 代表当前处理完了区间 1 ∼ i 1\sim i 1∼i ,且最后一个数的值为 j j j 下的最大序列长度,这是一个可解的 dp 方程,复杂度主要来源于枚举 j j j 的 O ( A i ) O(A_i) O(Ai) ,而枚举 i i i 的 O ( n ) O(n) O(n) 和转移的 O ( 1 ) O(1) O(1) 是无法省略的,所以尝试能否降低枚举 j j j 的复杂度。

显然,以 i i i 为结尾,向前按位或的可能情况最多有 i i i 种,复杂度降了,但还是不够。

进一步结合按位或的性质,可以发现,首先,向前的区间按位或值是单调不降的,且每一个二进制位变为 1 后就不会再变为 0 ,而什么时候不变,就是当当前按位或上来的数是区间按位或的子掩码时。那么显然,最多的变化次数就是 ⌈ log ⁡ 2 ( max ⁡ ( a 1 ∼ a i ) ) ⌉ \lceil \log_2(\max(a_1 \sim a_i))\rceil ⌈log2(max(a1∼ai))⌉ 次,这不会大于 30 。于是可以预处理每一个位置向前所有的按位或和。

现在枚举 j j j 的复杂度降了,只是转移时需要额外查找对应的按位或和是第几个,但复杂度依旧满足。

Code
cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

std::mt19937 rng(std::random_device{}());
typedef long double ld;
typedef long long ll;
typedef unsigned long long ull;

const int mod = 998244353;
const double ept = 1e-9;

ll add(ll x, const ll&y) { x += y; if(x >= mod) { x -= mod; } return x; }
ll sub(ll x, const ll&y) { x -= y; if(x < 0) { x += mod; } return x; }
ll mul(ll x, const ll&y) { x = x * y; if(x >= mod) { x %= mod; } return x; }

#ifndef ONLINE_JUDGE
#define DEBUG 1
#define fastio
#define coutd cout
#define db(i) cout << #i << ": " << i << endl;
#define dbl(fmt, ...) fprintf(stdout, fmt, ##__VA_ARGS__);
#define dbi(vec) { cout << #vec << ": "; for(auto &v: vec) { cout << v << ' '; } cout << endl; }
#define dbv(vec, a, b) { cout << #vec << ": "; for(int i=a; i!=b+sig(b-a); i+=sig(b-a)) { cout << vec[i] << ' '; } cout << endl; }
#else
#define DEBUG 0
#define fastio ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define coutd cerr
#define db(...)
#define dbl(fmt, ...)
#define dbi(vec)
#define dbv(vec, a, b)
#endif

int n;
int a[200200];
vector<int> b[200200];
int f[30][200200];
int dp[200200][100];
int lg2[200200];

void solve(int T) {
  cin >> n;
  for(int i=1; i<=n; i++) cin >> a[i];

  bool flag;
  for(int i=1; i<=n; i++) {
    b[i].push_back(a[i]);
    for(const auto &u: b[i-1]) {
      auto p = a[i] | u;
      flag = false;

      for(const auto &v: b[i]) if(v == p) { flag = true; break; }
      if(flag) continue;

      b[i].push_back(p);
    }
  }

  for(int j=1; j<=n; j++) f[0][j] = a[j];
  for(int i=1; i<30; i++)
    for(int j=1; j<=n; j++)
      f[i][j] = f[i-1][j] | f[i-1][min(j+(1<<(i-1)), n)];

  int ans = 1;
  dp[1][0] = 1;

  for(int i=1; i<n; i++) {
    for(int j=0; j<b[i].size(); j++) {
      if(dp[i][j] == 0) continue;

      int u = b[i][j] | a[i+1];
      for(int k=0; k<b[i+1].size(); k++)
        if(u == b[i+1][k]) {
          dp[i+1][k] = max(dp[i+1][k], dp[i][j]);
          break;
        }

      int l = i+1, r = n+1, mid, p;
      while(l < r) {
        mid = l + (r-l) / 2;
        p = lg2[mid-(i+1)+1];
        if((f[p][i+1]|f[p][mid-(1<<p)+1]) >= b[i][j]) r = mid;
        else l = mid + 1;
      }
      if(l > n) break;

      p = lg2[l-(i+1)+1];
      u = f[p][i+1] | f[p][l-(1<<p)+1];

      // cout << i << ' ' << l << ' ' << p << ' ' << u << endl;

      for(int k=0; k<b[l].size(); k++)
        if(u == b[l][k]) {
          dp[l][k] = max(dp[l][k], dp[i][j] + 1);
          ans = max(ans, dp[l][k]);
          break;
        }
    }
  }

  cout << ans << endl;
}

void init() {
  for(int i=2; i<=2e5; i++) lg2[i] = lg2[i/2] + 1;
}

signed main() {
    //freopen("1.in", "r", stdin);
    //freopen("1.out", "w", stdout);
    //cout.flags(ios::fixed); cout.precision(8);
    fastio
    init();
    int T_=1;
    // std::cin >> T_;
    for(int _T=1; _T<=T_; _T++) { solve(_T); }
    return 0;
}
相关推荐
ZhuNian的学习乐园1 天前
LLM对齐核心:RLHF 从基础到实践全解析
人工智能·python·算法
iAkuya1 天前
(leetcode)力扣100 31K个一组翻转链表(模拟)
算法·leetcode·链表
铭哥的编程日记1 天前
二叉树遍历的递归和非递归版本(所有题型)
算法
&永恒的星河&1 天前
告别过时预测!最新时序新SOTA:TimeFilter教会模型“选择性失明”
人工智能·深度学习·算法·时序预测·timefilter·时序算法
闻缺陷则喜何志丹1 天前
【二分查找】P9029 [COCI 2022/2023 #1] Čokolade|普及+
c++·算法·二分查找·洛谷
leiming61 天前
c++ set容器
开发语言·c++·算法
C雨后彩虹1 天前
猜密码问题
java·数据结构·算法·华为·面试
ullio1 天前
div1+2. 2180C - XOR-factorization
算法
岁岁的O泡奶1 天前
NSSCTF_crypto_[LitCTF 2024]common_primes
开发语言·python·算法