[HNOI2012]与非
Posted StaroForgin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[HNOI2012]与非相关的知识,希望对你有一定的参考价值。
与非
题解
显然,我们的
n
a
n
d
nand
nand是一种按位运算操作,我们发现我们可以通过
n
a
n
d
nand
nand来还原其他的基础位运算操作。
n
o
t
A
=
A
n
a
n
d
A
A
o
r
B
=
(
n
o
t
A
)
n
a
n
d
(
n
o
t
B
)
A
a
n
d
B
=
n
o
t
(
A
n
a
n
d
B
)
A
x
o
r
B
=
(
n
o
t
(
A
a
n
d
B
)
)
a
n
d
(
A
o
r
B
)
not\\,A=A\\,nand\\,A\\\\A\\,or\\,B=(not\\,A)\\,nand\\,(not\\,B)\\\\A\\,and\\,B=not\\,(A\\,nand\\,B)\\\\A\\,xor\\,B=(not\\,(A\\,and\\,B))\\,and\\,(A\\,or\\,B)
notA=AnandAAorB=(notA)nand(notB)AandB=not(AnandB)AxorB=(not(AandB))and(AorB)所以所有的能够让
a
a
a通过基础按位运算得到的数都可以通过
n
a
n
d
nand
nand得到。
而
A
n
a
n
d
B
A\\,nand\\,B
AnandB自身可以翻译做
n
o
t
(
A
a
n
d
B
)
not\\,(A\\,and\\,B)
not(AandB),所以通过基础按位运算得不到的数,都不可能通过
n
a
n
d
nand
nand操作得到。
所以我们只需要看看我们通过基础按位运算得到哪些数就可以了。
显然,这样的话我们很容易联想到线性基的形式,可以去尝试求出我们
a
a
a的基底。
由于我们可以采用所有的位运算,所以,如果任意两位的
1
1
1在所有的
a
a
a中出现情况一致,那么它们就必然属于同一个基。
于是,我们就能够
O
(
n
k
)
O\\left(nk\\right)
O(nk)地轻松求出所有的基底。
然后就可以用类似数位
d
p
dp
dp的方法来统计答案了,其实也就是直接贪心。
时间复杂度 O ( n k ) O\\left(nk\\right) O(nk)。
源码
#include<bits/stdc++.h>
using namespace std;
#define MAXN 2005
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
typedef long long LL;
typedef unsigned long long uLL;
typedef long double ld;
typedef pair<int,int> pii;
const LL INF=0x3f3f3f3f3f3f;
const int mo=1e9+9;
const int inv2=5e8+4;
const int jzm=233333333;
const int zero=100;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
const double eps=1e-5;
template<typename _T>
_T Fabs(_T x)return x<0?-x:x;
template<typename _T>
void read(_T &x)
_T f=1;x=0;char s=getchar();
while(s>'9'||s<'0')if(s=='-')f=-1;s=getchar();
while('0'<=s&&s<='9')x=(x<<3)+(x<<1)+(s^48);s=getchar();
x*=f;
template<typename _T>
void print(_T x)if(x<0)x=(~x)+1;putchar('-');if(x>9)print(x/10);putchar(x%10+'0');
int gcd(int a,int b)return !b?a:gcd(b,a%b);
int add(int x,int y,int p)return x+y<p?x+y:x+y-p;
void Add(int &x,int y,int p)x=add(x,y,p);
int qkpow(int a,int s,int p)int t=1;while(s)if(s&1)t=1ll*t*a%p;a=1ll*a*a%p;s>>=1;return t;
int n,K,tot,c[65];
LL L,R,a[MAXN],b[65],lim;
bool vis[65];
LL sakura(LL up)
if(up<0)return 0;LL now=0,res=0;
for(int i=K-1;i>=0;i--)
if(!vis[i]&&now+b[i]<=up)
now+=b[i],res+=(1LL<<c[i]-1);
return res+1LL;
signed main()
read(n);read(K);read(L);read(R);lim=(1LL<<K)-1LL;
for(int i=1;i<=n;i++)read(a[i]);
for(int i=K-1;i>=0;i--)
if(vis[i])continue;b[i]=lim;
for(int j=1;j<=n;j++)
if(a[j]&(1LL<<i))b[i]&=a[j];
else b[i]&=lim^a[j];
for(int j=0;j<i;j++)if(b[i]&(1LL<<j))vis[j]=1;
c[0]=!vis[0];for(int i=1;i<K;i++)c[i]=c[i-1]+(!vis[i]);
printf("%lld\\n",sakura(R)-sakura(L-1LL));
return 0;
谢谢!!!
以上是关于[HNOI2012]与非的主要内容,如果未能解决你的问题,请参考以下文章