动态规划,贪心 APIO 2015 Sculptures

  

 

  题意:给你一个长度为n的序列,你将它划分成k组,使得A<=k<=B,并且使每一组的和的或起来的值最小。

  可以考虑对答案的二进制位从高到低进行贪心,每次贪心用DP判断是否可以达成。

 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 using namespace std;
 5 const int maxn=2010;
 6 bool f[maxn][maxn],g[maxn][maxn],del[maxn][maxn];
 7 //del指一段区间和是否可取,g指一个dp决策是否可取
 8 bool G[maxn];
 9 int F[maxn];
10 //这里针对特殊数据改变DP方式,表示到当前位置最小分段的方案数
11 long long sum[maxn],ans;
12 int n,A,B,Maxk;
13 int main(){
14     freopen("sculpture.in","r",stdin);
15     freopen("sculpture.out","w",stdout);
16     scanf("%d%d%d",&n,&A,&B);
17     for(int i=1;i<=n;i++){
18         scanf("%lld",&sum[i]);
19         sum[i]+=sum[i-1];
20     }
21     if(A>1){
22         for(int k=47;k>=0;k--){
23             memset(f,0,sizeof(f));
24             f[0][0]=true;
25             for(int i=1;i<=n;i++)
26                 for(int j=0;j<i;j++)
27                     for(int l=1;l<=B;l++)
28                         if(!g[j][l-1]&&f[j][l-1]&&!((sum[i]-sum[j])&(1ll<<k))&&!del[j+1][i])
29                             f[i][l]=true;
30             
31             bool flag=false;
32             for(int l=A;l<=B;l++)
33                 if(f[n][l]&&!g[n][l])
34                     flag=true;
35             if(flag){
36                 for(int i=1;i<=n;i++)
37                     for(int l=1;l<=B;l++)
38                         if(!f[i][l])
39                             g[i][l]=true;
40                             
41                 for(int i=1;i<=n;i++)
42                     for(int j=0;j<i;j++)
43                         if((sum[i]-sum[j])&(1ll<<k))
44                             del[j+1][i]=true;
45             }
46             else
47                 ans+=1ll<<k;
48         }
49     }
50     else{
51         for(int k=47;k>=0;k--){
52             memset(F,127,sizeof(F));F[0]=0;
53             for(int i=1;i<=n;i++)
54                 for(int j=0;j<i;j++)
55                     if(F[j]!=2139062143&&!del[j+1][i]&&!G[j]&&!((1ll<<k)&(sum[i]-sum[j])))
56                         F[i]=min(F[i],F[j]+1);
57             
58             bool flag=false;            
59             if(!G[n]&&F[n]<=B)
60                 flag=true;
61             
62             if(flag==true){
63                 for(int i=1;i<=n;i++)
64                     for(int j=0;j<i;j++)
65                         if(F[i]>B)
66                             G[i]=true;
67                 
68                 for(int i=1;i<=n;i++)
69                     for(int j=0;j<i;j++)
70                         if((1ll<<k)&(sum[i]-sum[j]))
71                             del[j+1][i]=true;
72             }        
73             else        
74                 ans+=1ll<<k;
75         }
76     }
77     printf("%lld\n",ans);
78     return 0;
79 }

 

posted @ 2016-03-15 16:04  TenderRun  阅读(196)  评论(0编辑  收藏  举报