#Problem
把
n
n
n 个数分成
x
x
x 组,求每组和的最小按位或值(
A
<
=
x
=
B
A<=x=B
A<=x=B)
#Solution
错误dp…以此警示…
f
[
i
]
[
j
]
f[i][j]
f[i][j] 表示前
i
i
i 个数,分成
j
j
j 段的最小按位或值
f
[
i
]
[
j
]
=
m
i
n
(
f
[
k
]
[
j
−
1
]
∣
s
u
m
(
k
+
1
,
i
)
)
f[i][j]=min(f[k][j-1]|sum(k+1,i))
f[i][j]=min(f[k][j−1]∣sum(k+1,i))
虽说按位或会越来越小,但是可能出现或的内个值特别大,而前面我们如果取一个小的数,倒不如去一个大的数是后面都是0
考虑数位
d
p
dp
dp ,我们考虑这一位是否能是
0
0
0 ,也就是一个
b
n
d
bnd
bnd 的限制,结果就是
b
n
d
bnd
bnd 取个反就好啦
对于
n
<
=
100
n<=100
n<=100 的情况,我们定义
f
[
i
]
[
j
]
f[i][j]
f[i][j] 表示前
i
i
i 个数分成
j
j
j 段能否满足
b
n
d
bnd
bnd 的限制(即某些位确定为
0
0
0)。然后
b
n
d
bnd
bnd 成立的条件就是
f
[
n
]
[
A
]
f[n][A]
f[n][A]~
f
[
n
]
[
B
]
f[n][B]
f[n][B] 中有成立的即可
复杂度为
O
(
n
3
l
o
g
)
O(n^3log)
O(n3log)
但对于最后一个子任务…显然上面内个复杂度是做不了的
然而有一个特例
A
=
1
A=1
A=1
我们可以省去一维枚举分成的段数。用
d
p
[
i
]
dp[i]
dp[i] 表示前
i
i
i 个数满足
b
n
d
bnd
bnd 条件的最少分的段数。
如果
d
p
[
n
]
<
=
B
dp[n]<=B
dp[n]<=B 也就是说在满足
b
n
d
bnd
bnd 这个条件下,分的段数可以成立。
这样我们就可以把这道题解决了
#Code
#include <cstdio>
#include <cstring>
#include <map>
#include <algorithm>
using namespace std;
#define N 110
#define ll long long
#define inf 1ll<<60
int n,A,B,cnt=0,a[2010];
ll f[N][N],dp[2010];
ll sum[2010],ans=inf;
inline char gc(){
static char buf[1<<16],*S,*T;
if(S==T){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
return *S++;
}
inline int read(){
int x=0,f=1;char ch=gc();
while(ch<'0' || ch>'9'){if(ch=='-') f=-1;ch=gc();}
while('0'<=ch && ch<='9') x=x*10+ch-'0',ch=gc();
return x*f;
}
inline bool dp1(ll bnd){
memset(f,0,sizeof(f));
f[0][0]=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=i;++j)
for(int k=0;k<i;k++){
if(f[k][j-1] && !((sum[i]-sum[k])&bnd)){
f[i][j]=1;
}
}
for(int i=A;i<=B;i++) if(f[n][i]) return 1;
return 0;
}
inline void solve1(){
ll bnd=0;
for(int i=cnt-1;i>=0;i--){
bnd|=1ll<<i;
if(!dp1(bnd)) bnd^=1ll<<i;
}
printf("%lld\n",(1ll<<cnt)-1-bnd);
}
inline bool dp2(ll bnd){
for(int i=1;i<=n;i++) dp[i]=inf;dp[0]=0;
for(int i=1;i<=n;i++)
for(int j=0;j<i;++j)
if(dp[j]!=inf && !((sum[i]-sum[j])&bnd)){
dp[i]=min(dp[i],dp[j]+1);
}
if(dp[n]<=B) return 1;
return 0;
}
inline void solve2(){
ll bnd=0;
for(int i=cnt-1;i>=0;i--){
bnd|=1ll<<i;
if(!dp2(bnd)) bnd^=1ll<<i;
}
printf("%lld\n",(1ll<<cnt)-1-bnd);
}
int main(){
freopen("a.in","r",stdin);
n=read();A=read();B=read();
for(int i=1;i<=n;i++) a[i]=read(),sum[i]=sum[i-1]+a[i];
ll x=sum[n];
while(x) cnt++,x>>=1;
if(A==1) solve2();
else solve1();
return 0;
}