题目链接:CF981D
-
标签:按位、贪心、DP
-
大意:有n本书,每本书都有一个价值a。将这n本书按照顺序连续地放在书架上(读题的时候忽略了“连续的”这个重要讯息,导致很长时间都没有思路),定义一个书架的美观程度为这个书架上所有书价值的总和,k个书架的美观程度为每个书架的按位与和,求这k个书架的最大美观程度。
-
思路:先简单介绍一下按位与运算(自己对位运算不太熟悉老是碰壁)
-
按位与(&):运算规则:只有两个数的二进制同时为1,结果才为1,否则为0。(负数按补码形式参加按位与运算)
0 & 0= 0 ,0 & 1= 0,1 & 0= 0, 1 & 1= 1。
-
借机补充一个常用的运算:移位运算:(<</>>)效果很简单,就是数向左/右移一位,左移时在最右端补0,右移时在最左端补1,由二进制的性质可知:
n * 2 == (n << 1)
n / 2 ==(n >> 1)
1 << n == pow (2 , n) -
了解了按位与运算的特性后,我们不难由高位至低位进行贪心选择:如果最大位为1肯定要优于此位为0,而将多少个书放在一起,可以利用区间dp
-
dp[i][j]表示前i个书架放了j本书
-
-
代码:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int maxn=60;
LL dp[maxn][maxn],a[maxn];
LL sum[maxn],n,k;
int main() {
cin>>n>>k;
for(int i=1;i<=n;i++) {
cin>>a[i];
sum[i]=sum[i-1]+a[i];//计算前i项和
}
LL ans=0;
for(int bit=55;bit>=0;bit--) {//从最高位开始判断可否为1
LL num=(LL)1<<bit;//2的bit次方 (10000…0000)
memset(dp,0,sizeof(dp));
dp[0][0] = 1;
for(int l=1;l<=k;l++) {//放进k个书架里
for(int i=1;i<=n;i++) {//总共n本书
for(int j=0;j<i;j++) {//前一个书架放j本书
if(dp[l-1][j]&&((sum[i]-sum[j])&num)&&(((sum[i]-sum[j])&ans)==ans))
//如果前一个书架放j本书可行,且j+1~i号书之和(当前书架的和)的bit位是1,且不会令前置位丢1
dp[l][i] = 1;//该位置可行
}
}
}
if(dp[k][n]) ans+=num;
}
cout<<ans;
}
(第一次发现原来插入代码块的时候是可以选择语言的,难怪我之前的代码不亮了)