CF981D Bookshelves

Posted dreagonm

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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;
}

以上是关于CF981D Bookshelves的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces Avito Code Challenge 2018 D. Bookshelves

如何从后台弹出片段

cf 模拟

CF1435 游记

无法解析符号 c882c94be45fff9d16a1cf845fc16ec5

本人想学习破解技术但是看不懂反汇编代码!求助!!