题意

定义 NAND(与非)运算,其运算结果为真当且仅当两个输入的布尔值不全为真,也就是 A NAND B = NOT(A AND B) ,运算位数不会超过 \(k\) 位,

给你 \(n\) 个整数 \(A_i\) ,这些数能任意进行无数次与非运算,最后问能运算出多少个在 \([L, R]\) 区间的数。

\(k \le 60, n \le 1000, A_i < 2^k, 0 \le L \le R \le 10^{18}\)

题解

参考了 kczno1 孔爷的题解。

这个运算初看不太优美,其实我们可以利用它的一些性质。

由于 A NAND A = NOT (A AND A) = NOT A 所以我们就可以得到了 NOT (非) 运算。

进一步我们利用 NOTNOT(A NAND B) = NOT(NOT(A AND B)) = A AND B ,就可以得到了 AND (与)运算。

这样这个运算就变得十分优秀了,我们就转化成进行 NOTAND 然后我们就可以得到 所有二进制操作 了。

然后利用这个性质,我们就可以得到一个更加有用的性质。

对于第 \(i\) 位和第 \(j\) 位,如果所有 \(A_k\) 的第 \(i\) 位和第 \(j\) 位相同,那么最后的结果对于 \(i, j\) 这两位一定是一样的。

否则这两位的取值互不影响,可以任意取都能构造出一组合法方案。

我们就能把 \(k\) 位数划分成许多个等价类,每个等价类里面的元素取值都必须一样。

然后为了算 \([l, r]\) 区间的答案,我们令 \(Calc(r)\) 为 \(\le r\) 能凑出来的数。

那么答案为 \(Calc(r) - Calc(l - 1)\) 。至于如何算 \(Calc(x)\) 呢?我们按位考虑就行了。

  1. 具体的,如果枚举的位为 \(0\) ,那么忽略。

  2. 如果为 \(1\) ,假设这一位不能选,那么接下来以任意选而不会超也不会重复,所以方案数加上 \(2^{sum}\) ( \(sum\) 为接下来的集合的个数) 然后退出。

    如果能选。要么不选,那么 \(2^{sum-1}\) ;要么将集合中的数全部选了,再接着枚举后面。、

复杂度是 \(O(nk)\) 的,不知道为什么 \(n\) 只开 \(1000\) 。。。石乐志。

代码

#include <bits/stdc++.h>

#define For(i, l, r) for (register int i = (l), i##end = (int)(r); i <= i##end; ++i)
#define Fordown(i, r, l) for (register int i = (r), i##end = (int)(l); i >= i##end; --i)
#define Rep(i, r) for (register int i = (0), i##end = (int)(r); i < i##end; ++i)
#define Set(a, v) memset(a, v, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define debug(x) cout << #x << ": " << (x) << endl using namespace std; typedef long long ll; template<typename T> inline bool chkmin(T &a, T b) { return b < a ? a = b, 1 : 0; }
template<typename T> inline bool chkmax(T &a, T b) { return b > a ? a = b, 1 : 0; } template<typename T>
inline T read() {
T x(0), sgn(1); char ch(getchar());
for (; !isdigit(ch); ch = getchar()) if (ch == '-') sgn = -1;
for (; isdigit(ch); ch = getchar()) x = (x * 10) + (ch ^ 48);
return x * sgn;
} void File() {
#ifdef zjp_shadow
freopen ("2728.in", "r", stdin);
freopen ("2728.out", "w", stdout);
#endif
} typedef long long ll; const int N = 1e3 + 1e2, K = 60; ll a[N], sta[N], now, full; int n, k, sum[K]; inline ll Calc(ll x) {
if (x >= full) return 1ll << sum[k - 1];
ll res = 0;
for (int i = k - 1; x >= 0 && i >= 0; -- i)
if (x >> i & 1) {
if (sta[i]) {
res += 1ll << (sum[i] - 1); x -= sta[i];
}
else {
res += 1ll << sum[i]; break;
}
}
return res + (x == 0);
} int main () { File(); n = read<int>();
full = (1ll << (k = read<int>())) - 1; ll l = read<ll>(), r = read<ll>();
For (i, 1, n) a[i] = read<ll>(); ll have = 0;
Fordown (i, k - 1, 0) if (!(have >> i & 1)) {
ll now = full;
For (j, 1, n)
now &= (a[j] >> i & 1) ? a[j] : ~a[j];
have |= (sta[i] = now); sum[i] = 1;
}
For (i, 1, k - 1) sum[i] += sum[i - 1]; printf ("%lld\n", Calc(r) - Calc(l - 1)); return 0; }

BZOJ 2728: [HNOI2012]与非(位运算)的更多相关文章

  1. BZOJ 2728: [HNOI2012]与非

    2728: [HNOI2012]与非 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 786  Solved: 371[Submit][Status][ ...

  2. BZOJ 2728 HNOI2012 与非 高斯消元

    题目大意:给定k位二进制下的n个数,求[l,r]区间内有多少个数能通过这几个数与非得到 首先观察真值表 我们有A nand A = not A 然后就有not ( A nand B ) = A and ...

  3. 【BZOJ 2728】 2728: [HNOI2012]与非 (线性基?)

    2728: [HNOI2012]与非 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 813  Solved: 389 Description Inpu ...

  4. BZOJ 4245: [ONTAK2015]OR-XOR 贪心 + 位运算

    Description 给定一个长度为n的序列a[1],a[2],...,a[n],请将它划分为m段连续的区间,设第i段的费用c[i]为该段内所有数字的异或和,则总费用为c[1] or c[2] or ...

  5. HYSBZ(BZOJ) 4300 绝世好题(位运算,递推)

    HYSBZ(BZOJ) 4300 绝世好题(位运算,递推) Description 给定一个长度为n的数列ai,求ai的子序列bi的最长长度,满足bi&bi-1!=0(2<=i<= ...

  6. Java 位运算(移位、位与、或、异或、非)

    Java提供的位运算符有:左移( << ).右移( >> ) .无符号右移( >>> ) .位与( & ) .位或( | ).位非( ~ ).位异或( ...

  7. BZOJ 1087 互不侵犯King (位运算)

    题解:首先,这道题可以用位运算来表示每一行的状态,同八皇后的搜索方法,然后对于限制条件不相互攻击,则只需将新加入的一行左右移动与上一行相&,若是0则互不攻击,方案可行.对于每种方案,则用递推来 ...

  8. 【Java基础】3、Java 位运算(移位、位与、或、异或、非)

    public class Test { public static void main(String[] args) { // 1.左移( << ) // 0000 0000 0000 0 ...

  9. 【BZOJ2728】[HNOI2012]与非 并查集+数位DP

    [BZOJ2728][HNOI2012]与非 Description Input 输入文件第一行是用空格隔开的四个正整数N,K,L和R,接下来的一行是N个非负整数A1,A2……AN,其含义如上所述.  ...

随机推荐

  1. 【学习总结】win7下安装Ubuntu双系统的日常

    参考文献 1 - [双系统中删除linux(win7适用) ] 2 - [win7(32位)U盘安装.卸载ubuntu(64位)双系统] 3 - [Windows下安装Ubuntu 16.04双系统] ...

  2. php trait使用

    trait类似于基类  同样的方法优先级为 本类>trait>基类 <?php /** * Created by PhpStorm. * User: mac * Date: 2019 ...

  3. [转帖]Oracle 裁员史:技术人死于重组,卒于云计算

    Oracle 裁员史:技术人死于重组,卒于云计算 https://www.infoq.cn/article/tm-mcdHCPCI4eEwr6dbY 大厂裁员 我妈妈也总担心我没工作了 怎么还房贷 田 ...

  4. Linux 下面RPM 安装的SQLSERVER 修改字符集的方法

    1. 自己还是太low 2. 遇到问题 先 -h 处理 3. 发现登录报错, 怀疑是字符集的问题: 4. 计划是修改字符集 到 自己的环境可用的状态 使用命令 /opt/mssql/bin/mssql ...

  5. HDU 5898 odd-even number

    题目:odd-even number 链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=5898 题意:给一个条件,问l 到r 之间有多少满足条件的 ...

  6. 转《在浏览器中使用tensorflow.js进行人脸识别的JavaScript API》

    作者 | Vincent Mühle 编译 | 姗姗 出品 | 人工智能头条(公众号ID:AI_Thinker) [导读]随着深度学习方法的应用,浏览器调用人脸识别技术已经得到了更广泛的应用与提升.在 ...

  7. 区分Python中的可变对象和不可变对象

    参考: https://www.cnblogs.com/sun-haiyu/p/7096918.html """不过注意函数传参既不是传值也不是传引用,正确的叫法是传对象 ...

  8. C#中List<T>排序

    在面向对象开发过程中我们经常将一组对象放到一个特定集合中,此时我们通常使用泛型集合来存放,常见的如:List.Dictionary等.在使用这些泛型集合时我们有时需要对其进行排序,下面我们就一起学习下 ...

  9. Canvas & SVG

    Canvas & SVG https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-dev ...

  10. Yii2的save()方法容易出错的地方

    如果save()返回true, 但是数据没有保存成功,则应该是开启了事务且已经回滚 如果save()返回false, 则使用$model->errors查看错误原因 可以设置$model的场景, ...