首页 > 代码库 > Bzoj2728 [HNOI2012]与非

Bzoj2728 [HNOI2012]与非

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 753  Solved: 361

Description

技术分享

Input

输入文件第一行是用空格隔开的四个正整数N,K,L和R,接下来的一行是N个非负整数A1,A2……AN,其含义如上所述。 100%的数据满足K≤60且N≤1000,0<=Ai<=2^k-1,0<=L<=R<=10^18

Output

仅包含一个整数,表示[L,R]内可以被计算出的数的个数

Sample Input

3 3 1 4
3 4 5

Sample Output

4

HINT

 

样例1中,(3 NAND 4) NADN (3 NAND 5) = 1,5 NAND 5 = 2,3和4直接可得。

 

Source

day1

 

位运算 线性基 DP

一个数与非自己,结果等于非(Not)

Not(x Nand y) = x And y

not+and可以搞出所有逻辑运算。

可以据此从读入的数中找出所有线性基,然后由大到小使用线性基,进行数位DP。

 1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #define LL long long 6 using namespace std; 7 const int mxn=1010; 8 LL read(){ 9     LL x=0,f=1;char ch=getchar();10     while(ch<0 || ch>9){if(ch==-)f=-1;ch=getchar();}11     while(ch>=0 && ch<=9){x=x*10-0+ch;ch=getchar();}12     return x*f;13 }14 int n,k;15 LL L,R;16 LL a[mxn],b[mxn],p[mxn];17 int cnt=0;18 bool vis[mxn];19 LL solve(LL x){//数位DP 20     if(x==-1)return -1;21     int i;22     LL res=0,ans=0;23     for(i=1;i<=cnt;i++)24         if(res+p[i]<=x){25             res+=p[i];26             ans+=(1LL<<cnt-i);27         }28     return ans;29 }30 int main(){31     int i,j;32     n=read();k=read();L=read();R=read();33     LL ed=(1LL<<k)-1;34     for(i=1;i<=n;i++)a[i]=read();35     LL now=0;36     for(i=k-1;i>=0;i--){37         if(!vis[i]){38             now=ed;39             for(j=1;j<=n;j++){40                 if((a[j]>>i)&1)    now&=a[j];41                 else now&=(~a[j]);42             }43             for(j=0;j<=i;j++)44                 if((now>>j)&1)vis[j]=1;45             p[++cnt]=now;46         }47     }48     printf("%lld\n",solve(R)-solve(L-1));49     return 0;50 }51     

 

Bzoj2728 [HNOI2012]与非