做题的时候可能脑子里有根神经烧断了,把“与非”看成了“异或”,心头一喜,直接线性基一套,惨烈爆0。
不过线性基的思路还是很好的,与非能不能弄一个类似线性基的东西出来呢?
线性基是什么?
线代大佬一定很清楚,不过我是一个古代蒟蒻,所以不是很清楚。
现在我们有一堆数,我们要对他们随意做一个位运算,最后一定能得到若干不同的结果,形成结果集S。可能二进制位中有这么两位i和j,i取值定下来了,j的取值一定会定下来,才能保证这个数在S集中。
我们用我们可以使用的那个位运算操作整出若干个数,这若干个数可以操作运算得到(或曰:张成)结果集S,那么古代蒟蒻也不知道这个定义是否科学,我们暂时把这若干个数称为(伪)线性基。
与非是什么?
与非这个操作很神奇,因为:
NOT x=x NAND x
,所以NOT可以用与非表示。
x AND y=NOT(x NAND y)
,AND也可以被与非表示,然后所有的位运算操作都可以被表示了,譬如:
x OR y=(NOT x) NAND (NOT y)
和x XOR y=((NOT x)AND y)OR(x AND (NOT y))
显然,如果有两位i和j,在所有数中,第i位和第j位都一样,那么任何结果中,第i位和第j位都一样。
而其他的位就不受这样的约束条件了,因为我们可以这么构造(伪)线性基:对于第i位,我们枚举所有数
aj
a
j
,假设
aj
a
j
第i位为1,就AND
上
aj
a
j
,否则AND
上
aj
a
j
取反。这样的结果只有第i位和一定与第i位相同的位会是1,将这个结果记为
bi
b
i
。代码表示如下:
for(RI i=K-1;i>=0;--i)
if(!vis[i]) {
b[++tot]=bin[K]-1;//bin[i]:2的i次方
for(RI j=1;j<=n;++j)
if(a[j]&bin[i]) b[tot]&=a[j];
else b[tot]&=(a[j]^(bin[K]-1));
for(RI j=0;j<i;++j)
if(b[tot]&bin[j]) vis[j]=1;
}
这样操作后,我们得到了若干个数。由于OR
操作也是可以用NAND
进行的,假如我们要构造一个哪几位是1,而这几位之间没有约束的数,就直接将这些b给OR
起来即可。
现在开始求解,问题转化为小于等于R的结果数-小于等于L的(建议不看语言描述直接看代码理解)。
从高位往低位考虑。假设当前得到的结果是now,OR
上当前这个
bi
b
i
依然不会大于当前限制,那么不OR
这个
bi
b
i
,对于任何
bj(j>i)
b
j
(
j
>
i
)
,因为它的第i位及更高位不可能是1,所以OR
任意多个也不会比OR
上
bi
b
i
的结果大,所以不OR
bi
b
i
的话会有
2tot−i
2
t
o
t
−
i
个新的方案,继续考虑OR
了
bi
b
i
的方案数,就让nowOR
一下
bi
b
i
。假如会大于当前限制,肯定不能OR
,跳过即可。
LL dp(LL x) {
if(x==-1) return -1;
LL now=0,re=0;
for(RI i=1;i<=tot;++i)
if((now|b[i])<=x) now|=b[i],re+=bin[tot-i];
return re;
}
完整代码:
#include<bits/stdc++.h>
using namespace std;
#define RI register int
typedef long long LL;
LL L,R,ans,now;int n,K,js,tot;
LL bin[66],a[1005],b[66];int vis[66];
LL dp(LL x) {
if(x==-1) return -1;
LL now=0,re=0;
for(RI i=1;i<=tot;++i)
if((now|b[i])<=x) now|=b[i],re+=bin[tot-i];
return re;
}
int main()
{
scanf("%d%d%lld%lld",&n,&K,&L,&R);
for(RI i=1;i<=n;++i) scanf("%lld",&a[i]);
bin[0]=1;for(RI i=1;i<=K;++i) bin[i]=bin[i-1]<<1LL;
for(RI i=K-1;i>=0;--i)
if(!vis[i]) {
b[++tot]=bin[K]-1;
for(RI j=1;j<=n;++j)
if(a[j]&bin[i]) b[tot]&=a[j];
else b[tot]&=(a[j]^(bin[K]-1));
for(RI j=0;j<i;++j)
if(b[tot]&bin[j]) vis[j]=1;
}
printf("%lld\n",dp(R)-dp(L-1));
return 0;
}