9.25DAY1T2
2.巴厘岛的雕塑4401
【问题描述】
印尼巴厘岛的公路上有许多的雕塑,我们来关注它的一条主干道。
在这条主干道上一共有N座雕塑,为方便起见,我们把这些从1到N连续地进行标号,其中第i座雕塑的年龄是Yi年。为了使这条路的环境更加优美,政府想把这些雕塑分成若干组,并通过在组与之间种上一些树,来吸引更多的游客来巴厘岛。
下面是将雕塑分组的规则:
这些雕塑必须被分为恰好X组,其中A≤X≤B,每组必须含有至少一个雕塑,每个雕塑也必须属于且只一组。同一组中的所有雕塑必须 位于这条路的连续一段上。
当雕塑被分好组后,对于每个组,我们首先计算出该组所有雕塑的年龄和,然后计算将每组年龄和按位取或(即对上述年龄和按位取或),我们把按位取或后得到的结果称为这一分组的最终优美度(颜值)。
请问政府能得到的最小终优美度(颜值)是多少?
备注:
将两个非负数P和Q按位取或是这样进行计算的:
首先把P和Q转换成二进制:设nP是P的二进制位数,nQ是Q的二进制位数,M为nP和nQ中的最大值。P的二进制表示为pM-1,pM-2,…,p1,p0,Q的二进制表示为qM-1,qM-2,…,q1,q0,其中pi和qi分别是P和Q二进制表示下的第i位,第M-1位是数的最高位,第0位是数的最低位。
P与Q按位取或后的结果是:(pM-1或qM-1)(pM-2或qM-2)…(p1或q1)(p0或q0)。其中
:
0 或 0 = 0
0 或 1 = 1
1 或 0 = 1
1 或 1 = 1
【输入】
输入的第一行包含三个用空格分开的整数N,A和B。
第二行包含N个用空格分开的整数Y1,Y2,...,YN。
【输出】
输出一行一个数,表示最小的最终优美度。
【输入样例】
6 1 3 8 1 2 1 5 4
【输出样例】
11
【样例说明】
将这些雕塑分为2组,(8,1,2)和(1,5,4),它们的和是(11)和(10),最终优美是(11或10)=11。(不难验证,这也是最终优美度的最小值。)
【数据规模与约定】
共有五部分数据(或称5个子任务)。
第1部分数据占9分,数据范围满足:1≤N≤20,1≤A≤B≤N,0≤Yi≤1,000,000,000;
第2部分数据占16分,数据范围满足:1≤N≤20,1≤A≤B≤min(20,N),0≤Yi≤10;
第3部分数据占21分,数据范围满足:1≤N≤100,A=1,1≤B≤min(20,N),0≤Yi≤20;
第4部分数据占25分,数据范围满足:1≤N≤100,1≤A≤B≤N,0≤Yi≤1,000,000,000;
第5部分数据占29分,数据范围满足:1≤N≤2000,A=1,1≤B≤N,0≤Yi≤1,000,000,000。
"显然位运算的极值问题都应该从高位向低位考虑。优先让这一位为0,如果行的话这一位就是0,否则就设为1。"
设答案为ans,从高位到低位枚举 是否有使ans的这一位为0的方案,注意到每一位是互相独立的。假设枚举到了倒数第x位, 即ans的最高位到倒数第x+1位的最优01分布已确定,现在正在判断第x位是否有可能填0:
对于每个x,考虑递推法:
设 布尔数组 f[i][j]表示:将前i个数分j段,能否在 得到的优美度的最高位到倒数第x+1位 都与ans一致的情况下,让倒数第x位为0 因为段与段之间的合并为or运算,所以
递推方式为:
若 将前k个数(k<i)分j-1段,得到的优美度本身与ans一致,并且第j段的优美度也与 ans一致,才可以由f[k][j-1]转移到f[i][j] 如何判断以上两个条件:
1. 得到的优美度的最高位到倒数第k+1位 是否与ans一致:( (S[i]-S[k])>>k | ans ) == ans (ans为0的位,S[i]-S[k]都不为1)
2. 得到的优美度的倒数第k位能否为0:( (S[i]-S[k]) & 1<<(k-1) ) == 0 对于每个x,若f[n][A~B]有至少一个为1,nas的第k位就可以为0
复杂度:O( logY * n^3 )
对于最后一组数据:A==1,B<=n,段数只有上限 我们要想把f数组的第二个维度省掉的话,用f[i]记录将前i个数分段并得到可行解的最小段数,最后判断其是否小于B,即可。
复杂度:O( logY * n^2 )
注意:1写成1LL,开全局ll
code:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 typedef long long ll; 6 long long len=0; 7 long long s[1000005],f[2005][2005],g[200005]; 8 long long n,a,b,ans=0; 9 void work1(){ 10 for(int x=len;x>=1;x--){ 11 memset(g,0x3f3f3f3f,sizeof g); 12 g[0]=0; 13 for(int i=1;i<=n;i++){ 14 for(int j=0;j<i;j++){ 15 if(g[j]<b){ 16 int t=s[i]-s[j]; 17 if((t>>(ll)x|ans)==ans&&(t&(1ll<<(ll)(x-1)))==0)g[i]=min(g[i],g[j]+1); 18 } 19 } 20 } 21 if(g[n]>b){ 22 ans<<=1; 23 ans++; 24 } 25 else { 26 ans<<=1; 27 } 28 } 29 } 30 void work2(){ 31 for(long long x=len;x>=1;x--){ 32 memset(f,0,sizeof f); 33 f[0][0]=1; 34 for(long long i=1;i<=n;i++){ 35 for(long long j=1;j<=i;j++){ 36 for(long long k=0;k<i;k++){ 37 if(f[k][j-1]){ 38 long long t=s[i]-s[k]; 39 if(((t>>(ll)x)|ans)==ans&& (t&(1ll<<x-1ll))==0)f[i][j]=1; 40 } 41 } 42 } 43 } 44 int i; 45 for(i=a;i<=b;i++){ 46 if(f[n][i]) 47 break; 48 } 49 ans<<=1; 50 if(i>b)ans++; 51 // cout<<ans<<endl; 52 } 53 } 54 int main(){ 55 cin>>n>>a>>b; 56 for(long long i=1;i<=n;i++){ 57 cin>>s[i]; 58 s[i]+=s[i-1]; 59 } 60 for(int t=s[n];t>0;t>>=1) 61 len++; 62 if(a==1)work1(); 63 else work2(); 64 cout<<ans; 65 }