博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【BZOJ4069】[Apio2015]巴厘岛的雕塑 按位贪心+DP
阅读量:4698 次
发布时间:2019-06-09

本文共 2279 字,大约阅读时间需要 7 分钟。

【BZOJ4069】[Apio2015]巴厘岛的雕塑

Description

印尼巴厘岛的公路上有许多的雕塑,我们来关注它的一条主干道。
在这条主干道上一共有 N 座雕塑,为方便起见,我们把这些雕塑从 1 到 N 连续地进行标号,其中第 i 座雕塑的年龄是 Yi 年。为了使这条路的环境更加优美,政府想把这些雕塑分成若干组,并通过在组与组之间种上一些树,来吸引更多的游客来巴厘岛。
下面是将雕塑分组的规则:
这些雕塑必须被分为恰好 X 组,其中 A< = X< = B,每组必须含有至少一个雕塑,每个雕塑也必须属于且只属于一个组。同一组中的所有雕塑必须位于这条路的连续一段上。
当雕塑被分好组后,对于每个组,我们首先计算出该组所有雕塑的年龄和。
计算所有年龄和按位取或的结果。我们这个值把称为这一分组的最终优美度。
请问政府能得到的最小的最终优美度是多少?
备注:将两个非负数 P 和 Q 按位取或是这样进行计算的:
首先把 P 和 Q 转换成二进制。
设 nP 是 P 的二进制位数,nQ 是 Q 的二进制位数,M 为 nP 和 nQ 中的最大值。P 的二进制表示为 pM−1pM−2…p1p0,Q 的二进制表示为 qM−1qM−2…q1q0,其中 pi 和 qi 分别是 P 和 Q 二进制表示下的第 i 位,第 M−1 位是数的最高位,第 0 位是数的最低位。
P 与 Q 按位取或后的结果是: (pM−1  OR  qM−1)(pM−2 OR qM−2)…(p1 OR q1)(p0 OR q0)。其中:
0 OR 0=0
0 OR 1=1
1 OR 0=1
1 OR 1=1

Input

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

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

Output

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

Sample Input

6 1 3
8 1 2 1 5 4

Sample Output

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

HINT

 子任务 1 (9 分)

1< = N< = 20
1< = A< = B< = N
0< = Yi< = 1000000000
子任务 2 (16 分)
1< = N< = 50
1< = A< = B< = min{20,N}
0< = Yi< = 10
子任务 3 (21 分)
1< = N< = 100
A=1
1< = B< = N
0< = Yi< = 20
子任务 4 (25 分)
1< = N< = 100
1< = A< = B< = N
0< = Yi< = 1000000000
子任务 5 (29 分)
1< = N< = 2000
A=1
1< = B< = N
0< = Yi< = 1000000000

题解:考虑按位贪心来做。从高到低枚举答案的每一位,对于当前位,我们先check一下当前位=0能否满足要求,如果可以,则当前位=0,否则=1。那么如何check呢?考虑DP,用f[i][j]表示前i个雕塑分成j组是否可行,如果要求当前位=0可以满足要求,那么就把所有可能使得当前位!=0的转移都打上删除标记即可。

但是这样的转移时O(n^3)的啊,于是看了题解。。。md你告诉我最后一个子任务A=1!!!那么直接将DP方程该为f[i]表示将前i个雕塑最少能分成几组,然后转移就是O(n^2)的了。

 

#include 
#include
#include
using namespace std;typedef long long ll;int n,A,B;bool f[2][110],mp[2010][2010];int g[2010];ll ans,s[2010];bool check(ll v){ if(v<=8) { v++,v--; } int i,j,k,d; if(A==1) { memset(g,0x3f,sizeof(g)),g[0]=0; for(i=1;i<=n;i++) for(j=0;j
=A&&f[d][n]) return 1; } return 0;}inline int rd(){ int ret=0,f=1; char gc=getchar(); while(gc<'0'||gc>'9') {if(gc=='-')f=-f; gc=getchar();} while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar(); return ret*f;}int main(){ scanf("%d%d%d",&n,&A,&B); int i,j; for(i=1;i<=n;i++) s[i]=rd()+s[i-1]; for(ll k=1ll<<40;k;k>>=1) { if(check(k)) { for(i=1;i<=n;i++) for(j=0;j

 

转载于:https://www.cnblogs.com/CQzhangyu/p/7500504.html

你可能感兴趣的文章
Java语言程序设计(基础篇) 第十一章 继承和多态
查看>>
优秀程序员 分析提高能力 程序进阶
查看>>
javascript 获取图片原始尺寸
查看>>
关于JS中apply和call详细解答
查看>>
喜大普奔!Django官方文档终于出中文版了
查看>>
linux下导入、导出mysql数据库命令
查看>>
欧美很好听的调调
查看>>
c# 通用类扩展方法 备注
查看>>
POJ 3422 Kaka's Matrix Travels
查看>>
Testng 运行Cannot find class in classpath
查看>>
Linux2.6信号管理
查看>>
ASP.NET MVC 使用 Log4net 记录日志
查看>>
个人永久性免费-Excel催化剂插件功能修复与更新汇总篇之七
查看>>
Jquery调用C#后台方法
查看>>
TensorFlow中数据读取—如何载入样本
查看>>
php课程 10-35 php实现文件上传的注意事项是什么
查看>>
使用Python+md5删除本地重复(同一张不重名)的照片
查看>>
JAVA-java内存分配
查看>>
Centos6.4安装jdk
查看>>
javaweb各种乱码问题处理
查看>>