Codeforces 983B. XOR-pyramid【区间DP】

LINK

定义了一种函数f

对于一个数组b

当长度是1的时候是本身

否则是用一个新的数组(长度是原数组-1)来记录相邻数的异或,对这个数组求函数f

大概是这样的:

\(f(b[1]⊕b[2],b[2]⊕b[3],…,b[m−1]⊕b[m])\)

然后q次询问每次问一个区间的子区间里面最大的连续段的f函数值是多少


思路

首先考虑怎么快速计算f的函数值

因为我们发现一个\([l,r]\)的数组,考虑他最后状态的前一个状态

这个时候只有两个元素,而这两个元素实际上就是\([l,r-1]\)\([l +1,r]\)着两个区间的函数值

然后就把他们异或起来就可以了

最后再区间DP一下算每个区间的子区间内最大的

\(O(1)\)回答询问


#include<bits/stdc++.h>
using namespace std;
const int N = 5010;
int n, q, a[N];
int f[N][N], g[N][N];

void dp1() {
  for (int i = 1; i <= n; i++) f[i][i] = a[i];
  for (int len = 2; len <= n; len++) {
    for (int l = 1; l + len - 1 <= n; l++) {
      int r = l + len - 1;
      f[l][r] = f[l][r - 1] ^ f[l + 1][r];
    }
  }
}

void dp2() {
  for (int len = 1; len <= n; len++) {
    for (int l = 1; l + len - 1 <= n; l++) {
      int r = l + len - 1;
      g[l][r] = max(max(g[l][r - 1], g[l + 1][r]), f[l][r]);
    }
  }
}

int main() {
  scanf("%d", &n);
  for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
  dp1();
  dp2();
  scanf("%d", &q);
  while (q--) {
    int l, r;
    scanf("%d %d", &l, &r);
    printf("%d\n", g[l][r]);
  }
  return 0;
}
posted @ 2018-11-06 20:45  Dream_maker_yk  阅读(158)  评论(0编辑  收藏  举报