Description
给出n个数字,要求分成k个连续的子数组,使得每一堆总和按位与的结果是最大的
Solution
思路:dp + 贪心,首先意识到要结果最大需要按位贪心,从高位往低位取。其次,关于某一位是否能够实现,可以用 dp 去解决。具体实现如下:
令bool 变量 dp[i][d] 表示到第i个数字的时候已经分为d个连续子数组时,该二进制位是否能实现按位and后仍然为1.那么有
后面那一坨表示从j + 1 到 i 的前缀和在该二进制位上是否为1。
注意:题目给的 , 但是前缀和不一定在这个范围,需要多检测几位(第60位开始即可),不然会wrong answer
Code
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 1e6 + 5; ll a[65]; bool dp[65][65]; int n, k; bool solve(ll x) { memset(dp, false, sizeof(dp)); dp[0][0] = true; for(int i = 1; i <= n; i++) { for(int j = 0; j < i; j++) { for(int d = 1; d <= k; d++) { dp[i][d] |= (dp[j][d - 1] & (((a[i] - a[j]) & x) == x)); } } } return dp[n][k]; } int main() { ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr); cin >> n >> k; for(int i = 1; i <= n; i++) { cin >> a[i]; a[i] = a[i - 1] + a[i]; } ll ans = 0, res = 0; for(ll i = 60; i >= 0; --i) { res = (ans | (1LL << i)); if(solve(res)) { ans = res; } } cout << ans << '\n'; return 0; }