题意:给出$N$个范围在$[0,2^k-1]$的整数,定义位运算$NAND$为位运算$AND$的逆运算,求$[L,R]$中有多少数能成为若干个前面给出的整数、若干括号和$NAND$运算组成的表达式的结果(每一个数在一个表达式中可以出现多次)。
OI生涯第一道数位DP
可以使用$NAND$表示所有基本位运算(这个可以手玩出来qwq),那么$NAND$像基本位运算一样会有一个性质:如果所有给出的整数中第$i$位和第$j$位相同,那么最后的结果的第$i$位与第$j$位也一定相同,而不满足这个条件的位在一个确定了之后,另一位仍然可以同时取$0$或$1$(基于线性基的思想可以证明这个结论),那么我们可以预处理出所有互相影响的位,然后数位$DP$即可。
数位$DP$留在以后的专题??反正现在不想写,实在不懂看下面的code吧
1 #include<bits/stdc++.h> 2 #define ll long long 3 //This code is written by Itst 4 using namespace std; 5 6 inline ll read(){ 7 ll a = 0; 8 bool f = 0; 9 char c = getchar(); 10 while(c != EOF && !isdigit(c)){ 11 if(c == '-') 12 f = 1; 13 c = getchar(); 14 } 15 while(c != EOF && isdigit(c)){ 16 a = (a << 3) + (a << 1) + (c ^ '0'); 17 c = getchar(); 18 } 19 return f ? -a : a; 20 } 21 22 const int MAXN = 1010; 23 ll num[MAXN] , K , N , p[61]; 24 bool vis[MAXN]; 25 vector < int > influ[61]; 26 27 inline ll poww(ll a , int b){ 28 ll times = 1; 29 while(b){ 30 if(b & 1) 31 times = times * a; 32 a = a * a; 33 b >>= 1; 34 } 35 return times; 36 } 37 38 ll dfs(int now , ll sum , ll limit){ 39 if(now == -1 || !p[now]) 40 return 1; 41 if(vis[now]) 42 return dfs(now - 1 , sum , limit); 43 ll s = sum; 44 for(int i = 0 ; i < influ[now].size() ; i++) 45 s |= 1ll << influ[now][i]; 46 if(s <= limit) 47 return dfs(now - 1 , s , limit) + poww(2 , p[now] - 1); 48 else 49 return dfs(now - 1 , sum , limit); 50 } 51 52 int main(){ 53 #ifdef LG 54 freopen("3220.in" , "r" , stdin); 55 //freopen("3220.out" , "w" , stdout); 56 #endif 57 N = read(); 58 K = read(); 59 ll L = read() , R = read(); 60 for(int i = 1 ; i <= N ; i++) 61 num[i] = read(); 62 for(int i = K - 1 ; i >= 0 ; i--){ 63 if(vis[i]) 64 continue; 65 influ[i].push_back(i); 66 for(int j = i - 1 ; j >= 0 ; j--){ 67 if(vis[j]) 68 continue; 69 bool f = 1; 70 for(int k = 1 ; f && k <= N ; k++) 71 f = ((num[k] >> i) & 1) == ((num[k] >> j) & 1); 72 if(f){ 73 vis[j] = 1; 74 influ[i].push_back(j); 75 } 76 } 77 } 78 for(int i = 0 ; i < K ; i++) 79 p[i] = (i ? p[i - 1] : 0) + !vis[i]; 80 printf("%lld" , dfs(K - 1 , 0 , R) - (L ? dfs(K - 1 , 0 , L - 1) : 0)); 81 return 0; 82 }