CF-Avito Code Challenge 2018-D-Bookshelves
阿新 • • 發佈:2019-01-05
描述
題解
按位貪心,。
稍微詳細點說,那就是按照二進位制位從高位開始往低位貪心,貪心第 位時,檢查是否可以達成分為 堆,每堆和的第 位為 ,如果可以則累計。檢查的時候用 進行檢查,檢查的複雜度是 ,加上貪心的複雜度,一共是 , 的大小和 差不多,所以總得複雜度約莫是 ,這裡需要注意一下,最高位不能從 開始, 也不行,會被 (血淋淋的教訓),最好大於 ,因為最糟糕的情況時,給定 個數,分為一堆,每個數都是 ,那麼和就是 ,……,所以最好開大一些保險。
程式碼
#include <iostream>
#include <cstring>
using namespace std;
typedef long long ll;
const int MAXN = 70;
int n, k;
ll a[MAXN];
ll s[MAXN];
ll dp[MAXN][MAXN];
int main(int argc, const char * argv[])
{
cin >> n >> k;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
s[i] = s[i - 1] + a[i];
}
ll base_ = 0;
for (int bit = 60; bit >= 0; bit--)
{
ll cnt = 1ll << bit;
memset(dp, 0, sizeof(dp));
dp[0][0] = 1;
for (int i = 1; i <= k; i++) // i 堆
{
for (int j = 1; j <= n; j++) // 前 j 個數
{
for (int k = 0; k < j; k++) // 前 k < j 個數
{
if (dp[i - 1][k] && ((s[j] - s[k]) & cnt) && (((s[j] - s[k]) & base_) == base_))
{
dp[i][j] = 1;
}
}
}
}
if (dp[k][n])
{
base_ += cnt;
}
}
cout << base_ << '\n';
return 0;
}