题目描述

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

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

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

  • 这些雕塑必须被分为恰好 $X$ 组,其中 $A \leq X \leq B$,每组必须含有至少一个雕塑,每个雕塑也必须属于且只属于一个组。同一组中的所有雕塑必须位于这条路的连续一段上。
  • 当雕塑被分好组后,对于每个组,我们首先计算出该组所有雕塑的年龄和。
  • 计算所有年龄和按位取或的结果。我们这个值把称为这一分组的最终优美度。

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

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

  • 首先把 $P$ 和 $Q$ 转换成二进制。
  • 设 $n_P$ 是 $P$ 的二进制位数,$n_Q$ 是 $Q$ 的二进制位数,$M$ 为 $n_P$ 和 $n_Q$ 中的最大值。$P$ 的二进制表示为 $p_{M−1} p_{M−2} \dots p_1 p_0$,$Q$ 的二进制表示为 $q_{M−1} q_{M−2} \dots q_1 q_0$,其中 $p_i$ 和 $q_i$ 分别是 $P$ 和 $Q$ 二进制表示下的第 $i$ 位,第 $M − 1$ 位是数的最高位,第 $0$ 位是数的最低位。
  • $P$ 与 $Q$ 按位取或后的结果是: $(p_{M−1} \mathbin{\mathrm{OR}} q_{M−1})(p_{M−2} \mathbin{\mathrm{OR}} q_{M−2}) \dots (p_1 \mathbin{\mathrm{OR}} q_1) (p_0 \mathbin{\mathrm{OR}} q_0)$。其中:
    • $0 \mathbin{\mathrm{OR}} 0 = 0$
    • $0 \mathbin{\mathrm{OR}} 1 = 1$
    • $1 \mathbin{\mathrm{OR}} 0 = 1$
    • $1 \mathbin{\mathrm{OR}} 1 = 1$

输入格式

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

第二行包含 $N$ 个用空格分开的整数 $Y_1, Y_2, \dots, Y_N$。

输出格式

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


这道dp好大啊...........

我们分五个子任务分别来讨论一下


子任务

  • 子任务 1 (9 分)
    • $1 \leq N \leq 20$
    • $1 \leq A \leq B \leq N$
    • $0 \leq Y_i \leq 1000000000$
  • 分析

    暴枚分割点,有$n-1$个分割点,$O(2^{n-1}*n)$即可解决

  • 子任务 2 (16 分)
    • $1 \leq N \leq 50$
    • $1 \leq A \leq B \leq \min\{20, N\}$
    • $0 \leq Y_i \leq 10$
  • 分析

    观察到这个任务的特点,$Y_i$很小,我们可以考虑用dp的状态来记录$Y_i$

    $f[i][j][k]$表示前$i$个数,分成$j$组,和的或为$k$是否可行

    $O(n)$枚举每一个位置,对于每一个位置,$O(n^2)$枚举当前区间的开始位置和前面有几个区间,暴力转移

    时间复杂度$O(n^3*y)$

  • 子任务 3 (21 分)
    • $1 ≤ N ≤ 100$
    • $A = 1$
    • $1 \leq B \leq N$
    • $0 \leq Y_i \leq 20$
  • 分析

    观察到这个任务的特点,$Y_i$也比较小,而且$A=1$,显然刚才的状态数量过多,需要减少

    $f[i][j]$表示前$i$个数,和的或为$j$的最少分组,因为分组下届为$1$,那么,我们只要尽可能的减少分区,与$B$相比较,既可以得到最小的和的或了

    $O(n)$枚举每一个位置,对于每一个位置,$O(n)$枚举当前区间的开始位置,暴力转移

    时间复杂度$O(n^2*y)$

  • 子任务 4 (25 分)
    • $1 \leq N \leq 100$
    • $1 \leq A \leq B \leq N$
    • $0 \leq Y_i \leq 1000000000$
  • 分析

    可以发现,这其实是子任务2的升级版

    而这时,和的或状态显然已经记不下来了,这个时候我们考虑贪心

    我们按位来确定,显然,对于每一个要确定的位,只要他能$0$,就不可能让他$1$

    那么,我们贪心的确定最高位,根据最高位一次确定次高位......

    然后对于每一位,考虑用dp来验证

    假设当前为$0$,$f[i][j]$表示前$i$个数,分成$j$组,是否可行

    可行则为$0$,否则当前为只能为$1$,一次贪心地确定下去

    时间复杂度$O(n^3*logy)$

  • 子任务 5 (29 分)
    • $1 \leq N \leq 2000$
    • $A = 1$
    • $1 \leq B \leq N$
    • $0 \leq Y_i \leq 1000000000$

分析

和子任务4类似的,可以发现他是子任务3的升级版本

那么,同样按位贪心地确定

假设当前为$0$,$f[i]$表示前$i$个数,最少分组,当$f[n]\leq B$的时候,满足要求,当前为就设为$0$了,否则为$1$,依次确定下去

时间复杂度$O(n^2*logy)$

<br >

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<string>
#include<climits>
#include<vector>
#include<cmath>
#include<map>
#define LL long long
#define pii pair<int,int>
#define mp make_pair using namespace std; inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
return *p1++;
} inline void read(int &x){
char c=nc();int b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
} inline void read(LL &x){
char c=nc();LL b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
} inline int read(char *s)
{
char c=nc();int len=1;
for(;!(c>='a' && c<='z');c=nc()) if (c==EOF) return 0;
for(;(c>='a' && c<='z');s[len++]=c,c=nc());
s[len++]='\0';
return len;
} inline void read(char &x){
for (x=nc();!(x>='A' && x<='Z');x=nc());
} int wt,ss[19];
inline void print(int x){
if (x<0) x=-x,putchar('-');
if (!x) putchar(48); else {
for (wt=0;x;ss[++wt]=x%10,x/=10);
for (;wt;putchar(ss[wt]+48),wt--);}
}
inline void print(LL x){
if (x<0) x=-x,putchar('-');
if (!x) putchar(48); else {for (wt=0;x;ss[++wt]=x%10,x/=10);for (;wt;putchar(ss[wt]+48),wt--);}
} int n,A,B,b[50],f1[51][51][600],f3[110][110],f4[2010],ans[50];
LL Min,a[2010],f2[110][3000]; bool check()
{
int s=1;
for (int i=1;i<n;i++)
s+=b[i];
return (s>=A) && (s<=B);
} void pp(int x)
{
if (x==n)
{
if (check())
{
LL s=0,t=0;b[n]=1;
for (int i=1;i<=n;i++)
{
t=t+a[i];
if (b[i]==1) s|=t,t=0;
}
Min=min(Min,s);
}
return ;
}
for (int i=0;i<=1;i++)
b[x]=i,pp(x+1);
} int check(LL x,int z)
{
int y[50],s=0,j;
memset(y,0,sizeof(y));
while (x) y[++s]=x%2,x/=2;
for (int i=41;i>=z;i--)
if (!ans[i] && y[i]) return 0;
for (int i=41;i>=z;i--)
if (ans[i]!=y[i]) return 1;
return 2;
} bool check1(int x)
{
memset(f3,0,sizeof(f3));
f3[0][0]=2;
for (int i=1;i<=n;i++)
{
LL s=a[i];
for (int j=i-1;j>=0;j--)
{
int t=check(s,x);
if (t==1)
{
for (int k=0;k<=j;k++)
if (f3[j][k]) f3[i][k+1]=f3[j][k];
}
else if (t==2)
{
for (int k=0;k<=j;k++)
if (f3[j][k]) f3[i][k+1]=2;
}
s+=a[j];
}
}
for (int i=A;i<=B;i++)
if (f3[n][i]==2) return true;
return false;
} int check2(int x,LL y)
{
memset(f4,0,sizeof(f4));
for (int i=1;i<=n;i++)
f4[i]=n+1;
f4[0]=0;
for (int i=1;i<=n;i++)
{
LL s=a[i];
for (int j=i-1;j>=0;j--)
{
if (!(s&y))
f4[i]=min(f4[i],f4[j]+1);
s+=a[j];
}
}
return f4[n];
} int main()
{
read(n);read(A);read(B);
LL Max=0;
for (int i=1;i<=n;i++)
read(a[i]),Max=max(Max,a[i]);
if (n<=20)
{
Min=(1LL<<60)-1;
pp(1);
print(Min),puts("");
}
else if (n<=50 && Max<=10)
{
memset(f1,0,sizeof(f1));
f1[0][0][0]=1;
for (int i=1;i<=n;i++)
{
int s=a[i];
for (int j=i-1;j>=0;j--)
{
for (int k=0;k<=j;k++)
for (int p=0;p<=511;p++)
if (f1[j][k][p]) f1[i][k+1][p|s]=1;
s+=a[j];
}
}
Min=(1LL<<60)-1;
for (int i=A;i<=B;i++)
for (int j=0;j<=511;j++)
if (f1[n][i][j]) Min=min(Min,(LL)j);
print(Min),puts("");
}
else if (n<=100 && A==1 && Max<=20)
{
memset(f2,0,sizeof(f2));
for (int i=1;i<=n;i++)
for (int j=0;j<=2047;j++)
f2[i][j]=n+1;
for (int i=1;i<=n;i++)
{
int s=a[i];
for (int j=i-1;j>=0;j--)
{
for (int k=0;k<=2047;k++)
f2[i][k|s]=min(f2[i][k|s],f2[j][k]+1);
s+=a[j];
}
}
for (int i=0;i<=2047;i++)
if (f2[n][i]<=B) {print(i),puts("");return 0;}
}
else if (n<=100)
{
memset(ans,0,sizeof(ans));
for (int i=41;i>=1;i--)
if (check1(i)) ans[i]=0;else ans[i]=1;
Min=0;
for (int i=41;i>=1;i--)
Min=(Min<<1)+(LL)ans[i];
print(Min),puts("");
}
else
{
memset(ans,0,sizeof(ans));LL p=0;
for (int i=41;i>=1;i--)
if (check2(i,p|(1LL<<(i-1)))<=B) ans[i]=0,p|=1LL<<(i-1);else ans[i]=1;
Min=0;
for (int i=41;i>=1;i--)
Min=(Min<<1)+(LL)ans[i];
print(Min),puts("");
}
return 0;
}

【APIO2015】Bali Sculptures的更多相关文章

  1. UOJ#110. 【APIO2015】Bali Sculptures 贪心 动态规划

    原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ110.html 题解 我们发现n=2000 的子任务保证A=1! 分两种情况讨论: $n\leq 100$ ...

  2. UOJ#110. 【APIO2015】Bali Sculptures

    印尼巴厘岛的公路上有许多的雕塑,我们来关注它的一条主干道. 在这条主干道上一共有 NN 座雕塑,为方便起见,我们把这些雕塑从 11 到 NN 连续地进行标号,其中第 ii 座雕塑的年龄是 YiYi 年 ...

  3. uoj #111. 【APIO2015】Jakarta Skyscrapers

    #111. [APIO2015]Jakarta Skyscrapers 印尼首都雅加达市有 NN 座摩天楼,它们排列成一条直线,我们从左到右依次将它们编号为 00 到 N−1N−1.除了这 NN 座摩 ...

  4. 【UOJ #110】【APIO 2015】Bali Sculptures

    http://uoj.ac/problem/110 这道题subtask4和subtask5是不同的算法. 主要思想都是从高位到低位贪心确定答案. 对于subtask4,n比较小,设\(f(i,j)\ ...

  5. bzoj4069【APIO2015】巴厘岛的雕塑

    4069: [Apio2015]巴厘岛的雕塑 Time Limit: 10 Sec  Memory Limit: 64 MB Submit: 192  Solved: 89 [Submit][Stat ...

  6. 【数学建模】【APIO2015】Palembang Bridges

    Description 一条东西走向的穆西河将巴邻旁市一分为二,分割成了区域 A 和区域 B. 每一块区域沿着河岸都建了恰好 1000000001 栋的建筑,每条岸边的建筑都从 0 编号到 10000 ...

  7. 【BZOJ4069】【APIO2015】巴厘岛的雕塑 [贪心][DP]

    巴厘岛的雕塑 Time Limit: 10 Sec  Memory Limit: 64 MB[Submit][Status][Discuss] Description 印尼巴厘岛的公路上有许多的雕塑, ...

  8. 【APIO2015】Palembang Bridges

    题目描述 一条东西走向的穆西河将巴邻旁市一分为二,分割成了区域 $A$ 和区域 $B$. 每一块区域沿着河岸都建了恰好 $1000000001$ 栋的建筑,每条岸边的建筑都从 $0$ 编号到 $100 ...

  9. 【APIO2015】Jakarta Skyscrapers

    题目描述 印尼首都雅加达市有 $N$ 座摩天楼,它们排列成一条直线,我们从左到右依次将它们编号为 $0$ 到 $N − 1$.除了这 $N$ 座摩天楼外,雅加达市没有其他摩天楼. 有 $M$ 只叫做 ...

随机推荐

  1. Python 建模步骤

    #%% #载入数据 .查看相关信息 import pandas as pd import numpy as np from sklearn.preprocessing import LabelEnco ...

  2. MIP启发式算法:遗传算法 (Genetic algorithm)

    *本文主要记录和分享学习到的知识,算不上原创 *参考文献见链接 本文主要讲述启发式算法中的遗传算法.遗传算法也是以local search为核心框架,但在表现形式上和hill climbing, ta ...

  3. Alpha版(内部测试版)发布

    首先通过微信扫吗下载我们的软件校园服务,首先进去登录界面没账号点击注册,注册完就可以登录了,进去界面我们在二手交易这项功能里我们即可以事卖家又可以是买家如果我们卖东西点击商品出售,填写商品信息,商品图 ...

  4. loj2276 「HAOI2017」新型城市化

    给出的图是一个二分图(显然--吗),一个图的最大团=其补图的最大独立集,因此二分图的最大独立集就是补图的最大团. 欲使补图最大团变大,则要最大独立集变大.二分图最大独立集=点数-最小点覆盖.最小点覆盖 ...

  5. luogu1736 创意吃鱼法

    好的题解使人一下就懂啊-- s1[i][j]表示(i,j)最多向左(或右)延伸多少个格子,使这些格子中的数都是0(不包括(i,j)) s2[i][j]表示(i,j)最多向上延伸多少个格子,使这些格子中 ...

  6. jquery获得iframe内容的高度

    html: <iframe name="rightgp" id="right_frame_h" src="/Poster/rightgp&quo ...

  7. 自建NAS如何使用大于2TB的硬盘(从分区开始)

    目录 自建NAS如何使用大于2TB的硬盘(从分区开始) 对分区进行格式化 挂载到某一目录(需设置开机自动挂载) 上传文件测试: 补充 自建NAS如何使用大于2TB的硬盘(从分区开始) 需求说明: 自建 ...

  8. df和du显示的磁盘空间使用情况不一致问题

    背景介绍: dba同事删除了mysql /datao目录下的文件,通过du –sh查看空间使用700G,df -h查看空间使用1T,没有重启mysql服务. 另一个表现出du与df命令不同之处的例子如 ...

  9. 九度oj 题目1380:lucky number

    题目描述: 每个人有自己的lucky number,小A也一样.不过他的lucky number定义不一样.他认为一个序列中某些数出现的次数为n的话,都是他的lucky number.但是,现在这个序 ...

  10. ruby操作mysql

    require "win32ole" require 'pathname' require 'mysql2' excel = WIN32OLE.new('excel.applica ...