看到这种求位运算的问题一定要想直接对答案贪心啊,从高位枚举到低位,设当前的位为pos,pos之前贪心得到的答案为ans。
现在的问题就是能否找到一种方案,使得pos这一位为0,而且满足这种方案算出来的答案的前若干位与ans相同。
考虑设f[i][j]表示前i个数,分j份能否满足条件,0为满足,若存在一个k使得
f[k][j−1]==0,(s[i]−s[k])and(1<<pos)==0,(((ans|((s[i]−s[j])))>>pos))==(ans>>pos)
则f[i][j]=0.这样做是
n3log
的。
对于最后一个子任务,考虑到a=1,还是按位贪心,设g[i]表示前i个数至少分多少块满足条件,g[n]与b比较即可。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<map>
#include<climits>
#include<cmath>
#define DB double
#define X first
#define Y second
#define MP make_pair
#define INF 0x3f3f3f3f
#define LL long long
#define pii pair<int,int>
#define pll pair<LL,LL>
#define int LL
#define DEBUG(...) fprintf(stderr,__VA_ARGS__)
using namespace std;
template<typename T>void Read(T& x)
{
x=0;char c;int flag=0,sgn=1;
while(c=getchar())
{
if(c=='-')sgn=-1;
else if(c>='0'&&c<='9')x*=10,x+=c-'0',flag=1;
else if(flag)break;
}
x*=sgn;
}
const int MAXN=2001;
LL f[MAXN][MAXN],n,a,b,g[MAXN],ans=0,num[MAXN],s[MAXN];
void fucker()
{
f[0][0]=0;
for(int i=1;i<MAXN;i++)f[0][i]=1;
for(int pos=59;pos>=0;pos--)
{
if(pos==1)
pos=1;
int flag=1LL;
for(int k=1;k<=b;k++)
for(int i=k;i<=n;i++)
{
f[k][i]=1LL;
for(int j=k-1;j<i;j++)
{
bool a=(((s[i]-s[j])&(1LL<<(pos))))==0,b=((((ans|((s[i]-s[j])))>>pos))==(ans>>pos));
f[k][i]=min(f[k][i],f[k-1][j]==0&&a&&b?0LL:1LL);
}
}
for(int k=a;k<=b;k++)
if(f[k][n]==0)flag=0;
ans|=(flag<<pos);
}
cout<<ans<<endl;
}
void lover()
{
for(int pos=60;pos>=0;pos--)
{
for(int i=1;i<=n;i++)
{
g[i]=(LL)INF;
for(int j=0;j<i;j++)
{
int tmp=0;
bool a=((((s[i]-s[j])&(1LL<<pos)))==0),b=((((ans|((s[i]-s[j])))>>pos))==(ans>>pos));
if(a&&b)
tmp=g[j]+1;
else
tmp=3000;
//DEBUG("%lld %lld\n",g[i],tmp);
g[i]=min(g[i],tmp);
}
}
if(g[n]>b)ans|=(1LL<<pos);//printf("%lld\n",pos);
}
cout<<ans<<endl;
}
main()
{
freopen("bali.in","r",stdin);
freopen("bali.out","w",stdout);
Read(n),Read(a),Read(b);
for(int i=1;i<=n;i++)
Read(num[i]),s[i]=num[i]+s[i-1];
if(a==1)lover();
else fucker();
}