动态规划,贪心 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 }
尽最大的努力,做最好的自己!