• Codeforces 981D Bookshelves 【dp】【性质】


    这道题需要一点贪心,我们要找到每个书架价值&起来的最大值。从此出发可以想到最大值在二进制意义下如果高位可以取1,那么高位取1的数一定比高位不取1的数要大。如10000000大于01111111

    因此不难想到我们从最高位往下枚举每一位就可以了,那么我们现在要解决的问题是给一个数x,让我们判断n本书放在k个书架里能不能找到一个放的方式使得每个书架价值&起来是x

    由此想到用dp,我们dp[i][j],代表前i本书放进前j个书架里&价值能不能等于x(注意到实现的时候要在递归函数里带个参数x)。那转移方程怎么写呢?

    我们枚举k (k从j-1到i-1) ,如果dp(k,j-1,x) && ((sum[i]-sum[k])&x)==x,那dp[i][j]=1

    本质上我们枚举最后一个书架上放书的数量。比如我们遇到一个问题7本书放在5个书架里能不能&起来是x,那就是看( 4本书放在4个书架里,第五个书架放第5,6,7本书),( 5本书放在4个书架里,第五个书架放第6,7本书),( 6本书放在4个书架里,第五个书架放第7本书)这三个方案有没有任何一个方案使得书架&起来是x,如果有的话那returnn dp[7][5]=1

    最后考虑边界情况,如果j=1,那么 if( (sum[i]&x) ==x) return dp[i][j]=1 不然是0

    这里解释下sum[i]&x==x的意思,他指的是第一个书架放前i本书,判断书架价值&x等不等于x,如果等于x的话能就是合理的放书方式。

     1 #include<iostream>
     2 #include<cstring>
     3 using namespace std;
     4 
     5 long long sum[55],ans;
     6 int dp[55][55];//前i个书放进k个书架里&起来能不能等于check里的x
     7 
     8 bool check(int i,int j,long long x){
     9     if(dp[i][j]!=-1) return dp[i][j];
    10     if(j==1){
    11         if( (sum[i]&x) ==x) return dp[i][j]=1;
    12         return dp[i][j]=0;
    13     }
    14     for(int k=j-1;k<i;k++){
    15         if( check(k,j-1,x) && ((sum[i]-sum[k])&x)==x ) return dp[i][j]=1;
    16     }
    17     return dp[i][j]=0;
    18 } 
    19 
    20 int main(){
    21     int n,k; cin>>n>>k;
    22     for(int i=1;i<=n;i++) { cin>>sum[i]; sum[i]+=sum[i-1]; }
    23     
    24     for(int i=60;i>=0;i--){//枚举ans在二进制下的每一位
    25         memset(dp,-1,sizeof(dp));
    26         long long a=1; a=a<<i;
    27         if( check(n,k,ans+a) ) ans+=a;
    28     }
    29     cout<<ans<<endl;
    30     
    31     return 0;
    32 }
  • 相关阅读:
    钢镚开发的第7天
    钢镚儿开发的第六天
    钢镚儿开发的第五天
    钢镚儿开发第三、第四天
    4.18第九周学习进度
    人与神话阅读笔记02
    钢镚儿开发第二天
    热词云
    钢镚儿开发第一天
    [Usaco2006 Mar]Mooo 奶牛的歌声
  • 原文地址:https://www.cnblogs.com/ZhenghangHu/p/9109800.html
Copyright © 2020-2023  润新知