Codeforces981 D. Bookshelves(按位贪心+dp)

题意:

给定长度为n的序列a,要求分成不为空的k段
每一段的权值为元素和,
整个序列的权值为每一段权值的位运算与&的和
问序列分割后,整个的最大权值是多少

数据范围:n,k<=50,a(i)<=2^50

解法:

本来直接d[i][j]表示前i个数分成j段的最大总权值,瞎逼写了一个O(n^3)
写完发现傻逼了,与运算是不能直接取max转移的,不能这样直接dp

位运算的题基本都是从高位开始贪心
令d[i][j]表示i个书架,前j本书
能否在最高位不变的情况下使得当前位为1
对每一位dp判断一下即可

code:

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=55;
int d[maxm][maxm];
int sum[maxm];
int a[maxm];
int n,k;
int check(int x){
    for(int i=1;i<=n;i++){
        for(int j=1;j<=k;j++){
            d[i][j]=0;
        }
    }
    d[0][0]=1;
    for(int i=1;i<=n;i++){//i
        for(int j=1;j<=k;j++){//j
            for(int t=0;t<i;t++){//转移点t
                if((x&(sum[i]-sum[t]))==x){//保证高位答案不变
                    if(d[t][j-1])d[i][j]=1;//从d[t][j-1]转移到d[i][j]
                }
            }
        }
    }
    return d[n][k]==1;
}
signed main(){
    cin>>n>>k;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<=n;i++)sum[i]=sum[i-1]+a[i];
    int ans=0;
    for(int i=55;i>=0;i--){
        if(check(ans|(1LL<<i))){
            ans|=(1LL<<i);
        }
    }
    cout<<ans<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44178736/article/details/107790211