Codeforces 981D Bookshelves(按位贪心+二维DP)

题目链接:http://codeforces.com/contest/981/problem/D

题目大意:
给你n本书以及每本书的价值,现在让你把n本书放到k个书架上(只有连续的几本书可以放到一个书架上),
每个书架的价值值是书架上每本书的价值和,总的价值每个书架权值按位与的结果,要求输出最大的总价值。
解题思路:
按位从高到低枚举,每次都判断一下是否符合条件(即判断ans|(1<<i)是否能够取到),如果符合则更新答案。
判断过程:
设dp[i][j]表示将1~i分为j段是否符合条件,
然后枚举区间,状态转移方程为dp[i][j]|=dp[i-1][k-1],( ((a[j]-a[i])&ans)==ans,0<=i<j<=n )
最后只要判断dp[n][k]是否为1即可。

代码:

 1 #include<bits/stdc++.h>
 2 #define lc(a) (a<<1)
 3 #define rc(a) (a<<1|1)
 4 #define MID(a,b) ((a+b)>>1)
 5 #define fin(name)  freopen(name,"r",stdin)
 6 #define fout(name) freopen(name,"w",stdout)
 7 #define clr(arr,val) memset(arr,val,sizeof(arr))
 8 #define _for(i,start,end) for(int i=start;i<=end;i++)
 9 #define FAST_IO ios::sync_with_stdio(false);cin.tie(0);
10 using namespace std;
11 typedef long long LL;
12 const int N=1e2+5;
13 const int INF=0x3f3f3f3f;
14 const double eps=1e-10;
15 
16 int n,p;
17 LL a[N],dp[N][N];//dp[i][j]表示1~i分j段是否符合条件 
18 
19 bool check(LL x){
20     memset(dp,0,sizeof(dp));
21     dp[0][0]=1;
22     for(int k=1;k<=p;k++){
23         for(int i=0;i<n;i++){
24             for(int j=i+1;j<=n;j++){
25                 LL t=a[j]-a[i];
26                 if((t&x)==x&&dp[i][k-1]){
27                     dp[j][k]=1;
28                 }
29             }
30         }
31     }
32     return dp[n][p];
33 }
34 
35 int main(){
36     FAST_IO;
37     cin>>n>>p;
38     for(int i=1;i<=n;i++){
39         cin>>a[i];
40         a[i]+=a[i-1];
41     }
42     LL ans=0;
43     for(int i=60;i>=0;i--){
44         ans|=(1LL<<i);
45         if(!check(ans))
46             ans-=(1LL<<i);
47     }
48     cout<<ans<<endl;
49     return 0;
50 }

猜你喜欢

转载自www.cnblogs.com/fu3638/p/9131470.html
今日推荐