码迷,mamicode.com
首页 > 其他好文 > 详细

CF981D Bookshelves

时间:2018-11-01 17:46:35      阅读:348      评论:0      收藏:0      [点我收藏+]

标签:检查   i++   string   优先   and   统计   ret   直接   amp   

按位贪心+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

标签:检查   i++   string   优先   and   统计   ret   直接   amp   

原文地址:https://www.cnblogs.com/dreagonm/p/9890518.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!