话说莫非所有位运算都可以用贪心解决么……太珂怕啦……
一直把或运算看成异或算我傻逼……
考虑从高位到低位贪心,如果能使答案第$i$位为0那么肯定比不为$0$更优
然后考虑第$i$位是否能为$0$
设$f[i][j]$表示将前$i$个数分为$j$段,能否在最高位到第$i+1$位都与当前$ans$一致的情况下使第$i$位为0,可以的话$f[i][j]$为1,否则为0
考虑状态如何转移
如果$f[k][j-1]$为1且$sum[i]-sum[k]$的第$i$位为0则可以由$f[k][j-1]$转移到$f[i][j]$(其中$sum$表示前缀和)
考虑如何判断,如果$f[k][j-1]==1$且
(下面的$k$和上面那个$k$无关,因为变量有点多重复去了……)
$((sum[i]-sum[k])>>k|ans)== ans$(最高位到倒数第k+1位是否与ans一致)
$((S[i]-S[k])\&1<<(k-1))==0$(倒数第k位能否为0)
那么就可以转移了
对于每个$x$,若$f[n][A~B]$有至少一个为1,$ans$的第$k$位就可以为0
然后因为时间复杂度过不了最后一个子任务……所以$A=1$的时候特判一下……
具体来说就是因为段数只有上限,所以把$f$数组的第二维省掉,就能降一个n
1 //minamoto 2 #include3 #include 4 #include 5 #define ll long long 6 #define inf 0x3f3f3f3f 7 using namespace std; 8 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) 9 char buf[1<<21],*p1=buf,*p2=buf;10 template inline bool cmin(T&a,const T&b){ return a>b?a=b,1:0;}11 inline int read(){12 #define num ch-'0'13 char ch;bool flag=0;int res;14 while(!isdigit(ch=getc()))15 (ch=='-')&&(flag=true);16 for(res=num;isdigit(ch=getc());res=res*10+num);17 (flag)&&(res=-res);18 #undef num19 return res;20 }21 const int N=2005;22 ll sum[N];int f[105][105],g[N];23 ll ans=0,t;int n,l,r,len=0;24 void solve1(){25 int x,i,j;26 for(x=len;x;--x){27 for(i=1;i<=n;++i) g[i]=inf;28 for(i=1;i<=n;++i)29 for(j=0;j >(ll)x|ans)==ans&&(t&1ll<<(ll)x-1ll)==0) cmin(g[i],g[j]+1);33 }34 ans<<=1ll;35 if(g[n]>r) ++ans;36 }37 }38 void solve2(){39 int x,i,j,k;40 for(x=len;x;--x){41 memset(f,0,sizeof(f));42 f[0][0]=1;43 for(i=1;i<=n;++i)44 for(j=1;j<=i;++j)45 for(k=0;k >(ll)x|ans)==ans&&(t&1ll<<(ll)x-1ll)==0) f[i][j]=1;49 }50 for(i=l;i<=r;++i)51 if(f[n][i]) break;52 ans<<=1ll;53 if(i>r) ++ans;54 }55 }56 int main(){57 // freopen("testdata.in","r",stdin);58 n=read(),l=read(),r=read();59 for(int i=1;i<=n;++i)60 sum[i]=sum[i-1]+read();61 for(t=sum[n];t;t>>=1) ++len;62 l==1?solve1():solve2();63 printf("%lld\n",ans);64 return 0;65 }