[题解] CF1554B Cobb

​传送门​

题意

给出一个长度为 \(n\) 的数列,求出 \(i\times j-k\times (a_i|a_j)\) 的最大值。

解题报告

严格做法其它题解已经讲的很明白了,来一个玄学做法。

考场上就感觉这个东西肯定不是全扫过一遍的。

我们可以把结果分成两项来看:\(i\times j\) 和 \(k\times (a_i|a_j)\)。

我们希望前一部分尽量大,后一部分尽量小,考虑到 一个数按位或上另一个数数值不会减小,所以如果当前答案 \(ans\leq i\times (i-1)-k\times a_i\),那么就没必要往前扫描找到最大值。

否则的话,往前扫描更新 \(ans\)。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
template <typename T>
inline T read(){
T x=0;char ch=getchar();bool fl=false;
while(!isdigit(ch)){if(ch=='-')fl=true;ch=getchar();}
while(isdigit(ch)){
x=(x<<3)+(x<<1)+(ch^48);ch=getchar();
}
return fl?-x:x;
}
#define read() read<int>()
#define LL long long
const int maxn = 1e6 + 10;
int T,n;
LL a[maxn],ans,k;
int main(){
//freopen("1.in","r",stdin);
//freopen("1.out","w",stdout);
T=read();
while(T--){
ans=-0x7fffffffffffffff;
n=read();k=read<LL>();
for(int i=1;i<=n;i++)a[i]=read<LL>();
for(int i=n;i>1;i--){
if(ans<1LL*i*(i-1)-k*a[i]){
for(int j=i-1;j>=1;j--)ans=max(ans,1LL*i*j-k*(a[i]|a[j]));
}
}
printf("%lld\n",ans);
}
return 0;
}