CF981D 书架
1 CF981D 书架
2 题目描述
时间限制 \(1s\) | 空间限制 \(256M\)
\(Keks\) 先生是 \(Byteland\) 的典型白领。他在办公室有一个书架,上面放着一些书,每本书的价格都是正整数。\(Keks\) 先生把书架的价值定义为书架上的书的价格之和。\(Keks\) 先生获得了晋升,现在他正要搬到新办公室。他了解到在新办公室里,他会有 \(k\) 个书架。他认为 \(𝑘\) 个书架的美丽值是所有书架的价值按位与的结果。他决定不花时间重新排列所有的书籍,所以第一个书架上会摆上很多本第一批书,下一批次书摆在下一个书架上,以此类推。每个书架上最少有一本书。通过这种方式他把所有的书都放在 \(k\) 个书架上并且书架的美丽值尽可能大。请计算可能的最大美丽值。
3 题解
这道题中,我们考虑从高位到低位满足:高位答案为 \(1\) 比低位答案为 \(1\) 明显更优。对于当前位,我们可以设计 \(dp_{i, j}\) 表示前 \(i\) 本书放到前 \(j\) 个书架中能否满足当前答案(注意一定包括之前求出来的数,否则如果只看能否满足当前位 \(p\),可能导致无法满足之前的答案)。我们发现:如果只循环 \(i, j\) 两维貌似无法转移,因为我们不知道上一个书架结束的位置在哪里。因此,我们再枚举一维 \(l\),表示第 \(i\) 本书所位于的书架从第 \(l\) 本书开始。这样,我们只需要查看:\(ans \space \& \space \sum_{k = l}^{i}\limits a_i\) 是否等于 \(ans\),同时 \(dp_{l-1, j-1}\) 是否等于 \(1\)。如果这两个条件都满足,那么当前位就可以满足答案,\(dp_{i, j} = 1\)。
最后,我们的答案 \(ans\) 加上 \(dp_{n, k} * 2^p\) 即可。注意对于每一位要先把 \(dp\) 值清 \(0\)。
4 代码(空格警告):
#include <iostream>
#include <cstring>
using namespace std;
typedef long long ll;
const int N = 60;
#define int long long
int n, k, cnt, ans;
int a[N], sum[N], dp[N][N];
signed main()
{
cin >> n >> k;
for (int i = 1; i <= n; i++) cin >> a[i], sum[i] = sum[i-1] + a[i];
for (int p = N; p >= 0; p--)
{
memset(dp, 0, sizeof(dp));
dp[0][0] = 1;
cnt = ans + (1ll << p);
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= k; j++)
{
for (int l = 1; l <= i; l++)
{
if ((cnt & (sum[i] - sum[l-1])) == cnt && dp[l-1][j-1]) dp[i][j] = 1;
}
}
}
ans += dp[n][k] * (1ll << p);
}
cout << ans;
return 0;
}