UOJ#110. 【APIO2015】Bali Sculptures

时间:2017-04-19 00:39:21   收藏:0   阅读:405

印尼巴厘岛的公路上有许多的雕塑,我们来关注它的一条主干道。

在这条主干道上一共有 NN 座雕塑,为方便起见,我们把这些雕塑从 11 到 NN 连续地进行标号,其中第 ii 座雕塑的年龄是 YiYi 年。为了使这条路的环境更加优美,政府想把这些雕塑分成若干组,并通过在组与组之间种上一些树,来吸引更多的游客来巴厘岛。

下面是将雕塑分组的规则:

请问政府能得到的最小的最终优美度是多少?

备注:将两个非负数 PP 和 QQ 按位取或是这样进行计算的:

输入格式

输入的第一行包含三个用空格分开的整数 N,A,BN,A,B。

第二行包含 NN 个用空格分开的整数 Y1,Y2,,YNY1,Y2,…,YN。

输出格式

输出一行一个数,表示最小的最终优美度。

样例一

input

6 1 3
8 1 2 1 5 4

output

11

explanation

将这些雕塑分为 22 组,(8,1,2)(8,1,2) 和 (1,5,4)(1,5,4),它们的和是 (11)(11) 和 (10)(10),最终优美度是 (11OR10)=11(11OR10)=11。(不难验证,这也是最终优美度的最小值。)

子任务

时间限制1s

空间限制64MB

 

贪心 DP 位运算

“同一组中的所有雕塑必须位于这条路的连续一段上”←这个性质看上去科学而优雅,这使得我们可以DP分段。

答案是位运算的结果,那么可以考虑贪心,显然从高到低考虑每一位,当前位能填0就填0,最后的结果肯定比当前位填1小。

 

数据范围比较小,可以从高到低分别考虑答案的每一个二进制位:

  设f[考虑到第i个][分了j组]=当前位是否为0

  简单DP枚举分段位置,如果 f[k][j-1]==0 (k以前的部分都不会使得当前位为1)

  且  (sum[i]-sum[k])&(1<<pos)==0 (从k+1到i分成一段可行) 且 (((sum[i]-sum[k])|ans)>>pos) == (ans >> pos) (这么分组并不会改变更高位的答案)

  那么f[i][j]=0

 

最后一组数据n==2000,用上面的方法复杂度太高了。由于A==1,所以可以用另一种DP方程类似地求解,具体看代码

 

 1 /*by SilverN*/
 2 #include<algorithm>
 3 #include<iostream>
 4 #include<cstring>
 5 #include<cstdio>
 6 #define LL long long
 7 using namespace std;
 8 const int mxn=2010;
 9 int read(){
10     int x=0,f=1;char ch=getchar();
11     while(ch<0 || ch>9){if(ch==-)f=-1;ch=getchar();}
12     while(ch>=0 && ch<=9){x=x*10+ch-0;ch=getchar();}
13     return x*f;
14 }
15 int f[105][105];
16 LL a[mxn],smm[mxn];
17 int g[mxn];
18 LL ans=0;
19 int n,A,B;
20 void solve(){
21     for(int pos=45;pos>=0;pos--){
22         memset(f,1,sizeof f);
23         f[0][0]=0;
24         for(int i=1;i<=n;i++)//now
25             for(int j=1;j<=B;j++)//group
26                 for(int k=0;k<i;k++)
27                     if(f[k][j-1]==0 && (((smm[i]-smm[k])>>pos)&1)==0 && (((smm[i]-smm[k])|ans)>>pos)==(ans>>pos)){
28                         f[i][j]=0;
29                         break;
30                     }
31         bool flag=0;
32         for(int i=A;i<=B;i++)
33             if(f[n][i]==0){flag=1;break;}
34         if(!flag)ans|=1LL<<pos;
35     }
36     printf("%lld\n",ans);
37     return;
38 }
39 void solve2(){
40     for(int pos=51;pos>=0;pos--){
41         for(int i=1;i<=n;i++)g[i]=0x3f3f3f3f;
42         g[0]=0;
43         for(int i=1;i<=n;i++)
44             for(int j=0;j<i;j++){
45                 if((((smm[i]-smm[j])>>pos)&1))continue;
46                 if((((smm[i]-smm[j])|ans)>>pos)==(ans>>pos))g[i]=min(g[i],g[j]+1);
47             }
48         if(g[n]>B)ans|=1LL<<pos;
49     }
50     printf("%lld\n",ans);
51     return;
52 }
53 int main(){
54     int i,j;
55     n=read();A=read();B=read();
56     for(i=1;i<=n;i++){
57         a[i]=read();smm[i]=smm[i-1]+a[i];
58     }
59     if(A==1)solve2();    else solve();
60     return 0;
61 }

 

原文:http://www.cnblogs.com/SilverNebula/p/6731202.html

评论(0
© 2014 bubuko.com 版权所有 - 联系我们:wmxa8@hotmail.com
打开技术之扣,分享程序人生!