#110. 【APIO2015】Bali Sculptures
印尼巴厘岛的公路上有许多的雕塑,我们来关注它的一条主干道。
在这条主干道上一共有 NN 座雕塑,为方便起见,我们把这些雕塑从 11 到 NN 连续地进行标号,其中第 ii 座雕塑的年龄是 YiYi 年。为了使这条路的环境更加优美,政府想把这些雕塑分成若干组,并通过在组与组之间种上一些树,来吸引更多的游客来巴厘岛。
下面是将雕塑分组的规则:
- 这些雕塑必须被分为恰好 XX 组,其中 A≤X≤BA≤X≤B,每组必须含有至少一个雕塑,每个雕塑也必须属于且只属于一个组。同一组中的所有雕塑必须位于这条路的连续一段上。
- 当雕塑被分好组后,对于每个组,我们首先计算出该组所有雕塑的年龄和。
- 计算所有年龄和按位取或的结果。我们这个值把称为这一分组的最终优美度。
请问政府能得到的最小的最终优美度是多少?
备注:将两个非负数 PP 和 QQ 按位取或是这样进行计算的:
- 首先把 PP 和 QQ 转换成二进制。
- 设 nPnP 是 PP 的二进制位数,nQnQ 是 QQ 的二进制位数,MM 为 nPnP 和 nQnQ 中的最大值。PP 的二进制表示为 pM−1pM−2…p1p0pM−1pM−2…p1p0,QQ 的二进制表示为 qM−1qM−2…q1q0qM−1qM−2…q1q0,其中 pipi 和 qiqi 分别是 PP 和 QQ 二进制表示下的第 ii 位,第 M−1M−1 位是数的最高位,第 00 位是数的最低位。
- PP 与 QQ 按位取或后的结果是: (pM−1ORqM−1)(pM−2ORqM−2)…(p1ORq1)(p0ORq0)(pM−1ORqM−1)(pM−2ORqM−2)…(p1ORq1)(p0ORq0)。其中:
- 0OR0=00OR0=0
- 0OR1=10OR1=1
- 1OR0=11OR0=1
- 1OR1=11OR1=1
输入格式
输入的第一行包含三个用空格分开的整数 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。(不难验证,这也是最终优美度的最小值。)
子任务
- 子任务 1 (9 分)
- 1≤N≤201≤N≤20
- 1≤A≤B≤N1≤A≤B≤N
- 0≤Yi≤10000000000≤Yi≤1000000000
- 子任务 2 (16 分)
- 1≤N≤501≤N≤50
- 1≤A≤B≤min{20,N}1≤A≤B≤min{20,N}
- 0≤Yi≤100≤Yi≤10
- 子任务 3 (21 分)
- 1≤N≤1001≤N≤100
- A=1A=1
- 1≤B≤N1≤B≤N
- 0≤Yi≤200≤Yi≤20
- 子任务 4 (25 分)
- 1≤N≤1001≤N≤100
- 1≤A≤B≤N1≤A≤B≤N
- 0≤Yi≤10000000000≤Yi≤1000000000
- 子任务 5 (29 分)
- 1≤N≤20001≤N≤2000
- A=1A=1
- 1≤B≤N1≤B≤N
- 0≤Yi≤10000000000≤Yi≤1000000000
时间限制:1s1s
空间限制:64MB
#include<iostream> #include<cstdio> #include<cstring> #define maxn 110 using namespace std; int n,A,B,w[maxn],cnt; long long b[maxn],ans=1000000000000000LL; long long check(int sta){ long long res=0; cnt=1; b[1]=0; for(int i=1;i<n;i++){ b[cnt]+=w[i]; if(sta&(1<<(i-1))){ res|=b[cnt]; cnt++; b[cnt]=0; } if(cnt>B)return -1; } if(cnt<A)return -1; b[cnt]+=w[n]; res|=b[cnt]; return res; } int main(){ scanf("%d%d%d",&n,&A,&B); for(int i=1;i<=n;i++)scanf("%d",&w[i]); for(int i=0;i<(1<<(n-1));i++){ long long now=check(i); if(now!=-1) ans=min(ans,now); } cout<<ans<<endl; }
#include<iostream> #include<cstdio> #include<cstring> #define INF 0x3f3f3f3f #define maxn 2010 using namespace std; int f[105][105],g[maxn],n,A,B; long long a[maxn],sum[maxn],ans; void solve1(){ for(int pos=45;pos>=0;pos--){ memset(f,1,sizeof(f)); f[0][0]=0; for(int i=1;i<=n;i++) for(int j=1;j<=B;j++) for(int k=0;k<i;k++) if(f[k][j-1]==0 && (((sum[i]-sum[k])>>pos)&1)==0 && (((sum[i]-sum[k])|ans)>>pos)==(ans>>pos)){ f[i][j]=0; break; } bool flag=0; for(int i=A;i<=B;i++) if(f[n][i]==0){flag=1;break;} if(!flag)ans|=1LL<<pos; } cout<<ans<<endl; } void solve2(){ for(int pos=51;pos>=0;pos--){ for(int i=1;i<=n;i++)g[i]=INF; g[0]=0; for(int i=1;i<=n;i++) for(int j=0;j<i;j++){ if((((sum[i]-sum[j])>>pos)&1))continue; if((((sum[i]-sum[j])|ans)>>pos)==(ans>>pos)) g[i]=min(g[i],g[j]+1); } if(g[n]>B)ans|=1LL<<pos; } cout<<ans<<endl; } int main(){ scanf("%d%d%d",&n,&A,&B); for(int i=1;i<=n;i++){ cin>>a[i]; sum[i]=sum[i-1]+a[i]; } if(A==1)solve2(); else solve1(); return 0; }