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 = 5e4 + 5;
const int maxm = 5e3 + 5;
const int Max = 1e6+3;
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=0;i<n;i++){
        cin>>a[i];
    }
    for (int i=0;i<m;i++){
        cin>>L[i]>>R[i];
        L[i]--, R[i]--;
    }
    for (int i=1;i<Max;i++){
        Xor[i] = Xor[i-1] ^ i;
    }
    for (int i=0;i<n;i++){
        int maxx = 0;
        for (int j=i;j<n;j++){
            if (a[i] >= a[j]){
                maxx = max(maxx, Xor[a[i]] ^ Xor[a[j]-1]);
            }
            else{
                maxx = max(maxx, Xor[a[i]-1] ^ Xor[a[j]]);
            }
            b[j] = maxx;
        }
        for (int j=0;j<m;j++){
            if (L[j] <= i && R[j] >= i){
                ans[j] = max(ans[j], b[R[j]]);
            }
        }

    }
    for (int j=0;j<m;j++){
        cout << ans[j] << endl;
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值