CF1554B Cobb 题解

题意

题目链接

给定一个长度为 \(n\) 的数列 \(\{a_n\}\),试找到一个整数对 \((i,j)\),使得 \(ij-k(a_i|a_j)\) 最大,并输出最大值。(\(1\leq i<j\leq n\)

\(n\leq 10^5,0\leq k \leq \min(n,100),0\leq a_i\leq n\)

分析

暴力枚举是 \(O(n^2)\) 的,显然无法通过。

我们注意到,根据数学或的性质,显然 \(0\leq a_i|a_j\leq 2\max(a_i,a_j)\leq a_n\),那我们能否枚举 \(a_i|a_j\) 呢?

虽然这也不可取,不过这为我们打开了另一个思路。不难发现,\(ij\geq f(i,j)=ij-k(a_i|a_j)\geq ij-kn\),那么我们尝试给这个最大值设定一个下限,不妨为 \(f(n-1,n)=n(n-1)-k(a_{n-1}|a_n)\geq n(n-1)-2kn=n(n-2k-1)\)

那么,我们重新尝试枚举,发现左端点 \(l\) 至少得大于 \(n-2k-1\),否则所得到的函数值 \(f(l,j)\) 必然不会大于 \(f(n-1,n)\)。这样,我们就成功的将枚举的复杂度从 \(O(n^2)\) 压到了 \(O(k^2)\),能够成功 AC。

核心知识点:数学或的性质,\(a_i,k\) 的不寻常范围,数学分析

代码

#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 100010;
int n;
LL k, a[N];
LL solve() {
    cin >> n >> k;
    for (int i = 1; i <= n; ++i)
        cin >> a[i];
    LL res = -1e18;
    for (LL i = max(1LL, n - 2 * k); i < n; ++i)
        for (LL j = i + 1; j <= n; ++j)
            res = max(res, i * j - k * (a[i] | a[j]));
    return res;
}
int main()
{
    int T;
    cin >> T;
    while (T--) cout << solve() << endl;
    return 0;
}
posted @ 2022-03-03 15:34  cyhforlight  阅读(44)  评论(0编辑  收藏  举报