題意
- 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 ;
}