cf981 D. Bookshelves(贪心+dp)
题意:
把长为n的数组不重不漏地分成K个子段。每个子段的价值为段中所有数的和。求所有子段的价值的或和(按位或)
\(1\le k\le n \le 50, 0<a_i<2^{50}\)
思路:
一开始的错误做法:\(f(i,k,d)\) 记录把前 \(i\) 个数分成 \(k\) 段,二进制最高位是第 \(d\) 位的最大答案。最后答案在 \(f(n,K,all)\) 中取最大值。
这样做没考虑后效性。正解:从高到低,看能否凑出某一位。\(f(i,k)\) 表示把前 \(i\) 个数分成 \(k\) 段能否凑出ans的前几位
const int N = 55;
ll n, K, s[N], ans;
bool f[N][N];
bool ok(ll res)
{
memset(f, 0, sizeof f);
f[0][0] = 1;
for(int k = 1; k <= K; k++)
for(int i = 1; i <= n; i++)
for(int j = 0; j < i; j++)
if(f[j][k-1] && ((s[i]-s[j])&res)==res)
f[i][k] = 1;
return f[n][K];
}
signed main()
{
cin >> n >> K;
for(int i = 1; i <= n; i++)
cin >> s[i], s[i] += s[i-1]; //前缀和
for(ll i = N; i >= 0; i--)
if(ok( ans|(1ll<<i) )) ans |= (1ll<<i);
cout << ans;
}

浙公网安备 33010602011771号