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 }