天天看点

Codeforces 620F Xors on Segments DP

题意

  • n个数,m次查询。n<=5e4,m<=1e3
  • 每次查询为一个区间l,r,要在n的数的[l,r]区间内选出2个数a,b(a<=b)
  • 计算f(a, b) = a^(a+1)^(a+2)^…^b,输出最大的这个值

思路

  • 我想了好久,想到用莫队+Trie树了。。可是还是没想出来。。标程好像也是这样。。不过我没细看。。之后我会再尝试用这个方法解决~
  • 我参考了大神的博客,看到居然O(n^2)也能过。。。然后就写了一发过了。。
  • 基本想法就是,离线算法,计算每个(i,j)的最大值,然后如果查询问道,就更新这个查询的ans
  • 但是呢,如果朴素的计算每个(i,j),复杂度要O(n^3)是不行的。
  • 我们注意到,实际我们需要计算的只有对任意a[i]和a[j](设min(a[i], a[j]) = x, max(a[i], a[j]) = y),f(x, y),这个单独计算每一组预处理之后是O(1)的,所以呢我们只需要枚举i, j即可算出所有这样的f(x, y),复杂度是O(n ^ 2)
  • 然后,由于我们存不下这么多对的解,所以要考虑如何更新ans了,这里有点dp的想法
  • dp(i,j)表示,在[i, j]区间内,必须用到i的最大值,dp(i, j) = max(dp(i,j-1), f(a[i], a[j]) )
  • 这个dp可以滚动数组,压掉i这一维
  • 对于第j组的查询,L[j], R[j], ans[j] = max(dp(i, R[j]) ) 其中L[j] <= i <= R[j]

实现

#include <bits/stdc++.h>
using namespace std;
const int maxn =  + ;
const int maxm =  + ;
const int Max = +;
int L[maxm], R[maxm];
int a[maxn], b[maxn];
int Xor[Max];
int ans[maxm];

int main(){
    int n,m;
    ios::sync_with_stdio(false);
    cin>>n>>m;
    for (int i=;i<n;i++){
        cin>>a[i];
    }
    for (int i=;i<m;i++){
        cin>>L[i]>>R[i];
        L[i]--, R[i]--;
    }
    for (int i=;i<Max;i++){
        Xor[i] = Xor[i-] ^ i;
    }
    for (int i=;i<n;i++){
        int maxx = ;
        for (int j=i;j<n;j++){
            if (a[i] >= a[j]){
                maxx = max(maxx, Xor[a[i]] ^ Xor[a[j]-]);
            }
            else{
                maxx = max(maxx, Xor[a[i]-] ^ Xor[a[j]]);
            }
            b[j] = maxx;
        }
        for (int j=;j<m;j++){
            if (L[j] <= i && R[j] >= i){
                ans[j] = max(ans[j], b[R[j]]);
            }
        }

    }
    for (int j=;j<m;j++){
        cout << ans[j] << endl;
    }
    return ;
}