Bzoj2728 [HNOI2012]与非
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
3 4 5
Sample Output
4
HINT
样例1中,(3 NAND 4) NADN (3 NAND 5) = 1,5 NAND 5 = 2,3和4直接可得。
Source
位运算 线性基 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
本文为博主原创文章,转载请注明出处。