【bzoj2728】[HNOI2012]与非
2016-03-25 21:00
260 查看
先打出nand表
0 nand 0=1
1 nand 1=0
0 nand 1=1
1 nand 0=1
容易发现(!a)=a nand a
然后(a&b)=!(a nand b)
然后(a|b)=!((!a)&(!b))
然后(a^b)=(a|b)&(a nand b)
所以通过nand我们可以实现任意一种位运算
所以每一位我们想得到0/1都是可以的
按道理[L,R]中符合位数要求的数都能得到
然而我们发现这样一个显然的结论:
如果A序列中每个数的第i位和第j位都相等,那么不论怎么nand,我们得到的数的第i位和第j位一定会相等。
不妨设这种限制条件为(i,j)。
于是我们统计[L,R]中符合这个限制条件的数即可。
首先从高位找x的第一个1,进行决策。
如果我们不选这个1,那么剩下的未决策位可以随便取,答案加上2^未决策位数。
如果我们选这个1,那么从这个1开始接下来一段的0必须取0(取1的话一定是大于R的数),于是直接考虑下一个1的决策。
再考虑限制条件。我们设xd[i]=符合(i,j)限制的最小j,那么决策第i位为1时,我们也会决策第xd[i]位必须为1。必须取0的决策同理。
如果准备决策某一位,发现其已经被限制,则我们需要判断一下,如果已有限制与当前要给它的决策一致,则不用管了。如果希望决策它为1但它必须为0,那么这一位我们只能决策它为0,加上答案,后面的1都不用再枚举了。如果希望决策它为0但它必须为1,那么说明没办法决策出符合要求的数,直接break。
这样得到的是[0,x-1]中符合要求的数,因为我们不选第一个1就可以决策到0,然而我们决策完最后一个1也决策不出x。
答案就是query(r+1)-query(l)。
(以上来自XZY大神犇空间。。。)
0 nand 0=1
1 nand 1=0
0 nand 1=1
1 nand 0=1
容易发现(!a)=a nand a
然后(a&b)=!(a nand b)
然后(a|b)=!((!a)&(!b))
然后(a^b)=(a|b)&(a nand b)
所以通过nand我们可以实现任意一种位运算
所以每一位我们想得到0/1都是可以的
按道理[L,R]中符合位数要求的数都能得到
然而我们发现这样一个显然的结论:
如果A序列中每个数的第i位和第j位都相等,那么不论怎么nand,我们得到的数的第i位和第j位一定会相等。
不妨设这种限制条件为(i,j)。
于是我们统计[L,R]中符合这个限制条件的数即可。
首先从高位找x的第一个1,进行决策。
如果我们不选这个1,那么剩下的未决策位可以随便取,答案加上2^未决策位数。
如果我们选这个1,那么从这个1开始接下来一段的0必须取0(取1的话一定是大于R的数),于是直接考虑下一个1的决策。
再考虑限制条件。我们设xd[i]=符合(i,j)限制的最小j,那么决策第i位为1时,我们也会决策第xd[i]位必须为1。必须取0的决策同理。
如果准备决策某一位,发现其已经被限制,则我们需要判断一下,如果已有限制与当前要给它的决策一致,则不用管了。如果希望决策它为1但它必须为0,那么这一位我们只能决策它为0,加上答案,后面的1都不用再枚举了。如果希望决策它为0但它必须为1,那么说明没办法决策出符合要求的数,直接break。
这样得到的是[0,x-1]中符合要求的数,因为我们不选第一个1就可以决策到0,然而我们决策完最后一个1也决策不出x。
答案就是query(r+1)-query(l)。
(以上来自XZY大神犇空间。。。)
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
using
namespace
std;
typedef
long
long
LL;
LL k,n,l,r;
LL a[1010<<2];
int
s[110],xd[110];
int
res;
bool
flag(
true
);
bool
check(
int
i,
int
j)
{
for
(
int
m=1;m<=n;m++)
if
(((a[m]>>i) ^ (a[m]>>j)) & 1)
return
false
;
return
true
;
}
LL query(LL x)
{
LL ans=0;
if
(x>=(1LL<<k))
return
1LL<<res;
int
u,v=res;
for
(
int
i=0;i<=64;i++)
s[i]=2;
for
(
int
i=k-1;i>=0;i--)
{
u=xd[i];
if
((x>>i) & 1)
{
if
(s[u]==2)
s[u]=1,v--,ans+=(1LL<<v);
else
if
(s[u]==0)
{
ans+=(1LL<<v);
break
;
}
}
else
if
(s[u]==2)
s[u]=0,v--;
else
if
(s[u]==1)
break
;
}
return
ans;
}
int
main()
{
scanf
(
"%lld%lld%lld%lld"
,&n,&k,&l,&r);
for
(
int
i=1;i<=n;i++)
scanf
(
"%lld"
,&a[i]);
for
(
int
i=0;i<=k-1;i++)
{
int
j;
for
(j=0;j<=i-1;j++)
if
(check(i,j))
{
xd[i]=j;
break
;
}
if
(i==j)
xd[i]=i,res++;
}
LL s1=query(r+1);
LL s2=query(l);
printf
(
"%lld"
,s1-s2);
return
0;
}
相关文章推荐
- 【bzoj1260】[CQOI2007]涂色paint
- POJ 1847 Tram dij
- 1319 - Monkey Tradition
- Android课程---布局管理器之相对布局(二)
- java 中的Number类 Character类 String类 StringBuffer类 StringBuilder类
- Leetcode 115. Distinct Subsequences
- 类似最集合中最大子序列 hdu 2668
- C++ 指针与const的组合复习
- Eclipse常用快捷键
- android开发带下划线的多行文本框
- 无符号整型赋值陷阱
- 【bzoj2003】[Hnoi2010]Matrix 矩阵
- bzoj 3091 城市旅行(LCT+数学分析)
- C++ 类成员函数继承(virtual、非virtual)
- 高可用
- 【bzoj1028】[JSOI2007]麻将
- MLlib1.6指南笔记
- KVC/KVO的实现原理简述
- eclipse实现Java源代码查看
- #怎样在Matlab中画柠檬