CF981D Bookshelves

按位贪心+DP的好题qwq

首先看到题目的要求,统计价值的时候的操作是按位与,就要有按位分别计算的意识

开始没意识到结果想了好久还是看了题解才想到

由于统计价值的方式不是加和,所以可能会出现两个较大的值AND起来更小甚至变成0,所以不能直接DP

考虑按位贪心

显然高位为1后的值一定比高位不为1的值要大,所以从高位向下贪心,每次检查能否在使前i个位值不变的情况下,使新加入的位变为1

检查的时候用区间dp实现即可

\(dp[i][j]\)表示前j本书分到前i个书架上是否能使前面的位不变且当前检查的位为1

状态转移方程为:

dp[i][j]|=dp[i-1][kx]&&(((sum[j]-sum[kx])&&x)==x) 

总的复杂度是\(O(n^{2}k)\)

注意位运算优先级和枚举的最高位的位数

代码


#include <cstdio>
#include <cstring>
#include <algorithm>
#define int long long
using namespace std;
int n,k,a[51],sum[51],dp[51][51],ans=0;
int check(int x){
    memset(dp,0,sizeof(dp));
    dp[0][0]=1;
    for(int i=1;i<=k;i++)
        for(int j=1;j<=n;j++)
            for(int kx=0;kx<j;kx++)
                dp[i][j]|=dp[i-1][kx]&&(((sum[j]-sum[kx])&x)==x);
    return dp[k][n];
}
signed main(){
    scanf("%lld %lld",&n,&k);
    for(int i=1;i<=n;i++)
        scanf("%lld",&a[i]);
    for(int i=1;i<=n;i++)
        sum[i]=sum[i-1]+a[i];
    for(int i=60;i>=0;i--){
        int mid=ans|(1LL<<i);
        if(check(mid))
            ans|=(1LL<<i);
    }
    printf("%lld",ans);
    return 0;
}

posted @ 2018-11-01 17:27  dreagonm  阅读(589)  评论(0编辑  收藏  举报