序:这篇论文起初第一眼看的时候觉得没什么用处,后来CYY说这篇写的还是不错的,于是花了一天仔细看了看
就把文中一些比较重要的结论和思想列出来当作回忆
1.1 读取某一位 pos: x>>pos&1
1.2 改变某一位 pos: 变为1:x|(1<<pos)
变为0:x&~(1<<pos)
取反:x^(1<<pos)
2.1 求1的个数:
利用分治的思想,将32个1字节的转变为16个2字节再转化直到1个32字节的 也就是答案
再利用因为其个数限制不会爆一些字节 于是进行代码缩短
具体证明:见论文
3.1求前缀/后缀0的个数
列出求前缀方法,后缀方法类似
这里主要用到的就是二分的思想,
先判断高16位是否为0,如果x>>16为0,则前16位为前缀0,于是在1--15位上二分即可,
否则只有高16位一位为0,于是x>>16位再接着二分即可
4.1求第k个1的位置
于是我们利用二分和文中提的一种差表法即可
5.1提取末尾连续的1
我们考虑在最后+1,最右边连续的1会变成0,于是我们可以利用这个性质得出公式
x&(x^(x+1))
6.1 lowbit(i)
定义:i在二进制下保留最低位1的二进制
公式:
前两个利用到5.1相反的性质,一个数-1,最右边连续的1会变成0
最后一个则利用补码的性质,也是最常用的
7.1本文最重要的用于实现题目简化的数据结构也就是bitset
加入、删除为 o(1) 的
取交集、并集、1的个数等为o(n/w)的 w为进制长宽
8.1枚举子集
考虑将子集大小排序输出就可以了,于是我们每次输出比x小1的子集y,再由y输出y‘....
y=x&(x-1); x=y;
9 T
9.1 筷子
2n+1个数 某个数x出现次数为奇数,其余的为偶数,求x
Sor:直接将所有数^起来即可
9.2 Codeforces 97D
Sor:我们考虑对于这个图建一个set,于是我们考虑每个点对应
set中的第i*m+j个,于是我们的上下左右移动也就转变为
>>m 、<<m 、<<1 、>>1 于是我们就可以利用这个来
模拟即可
9.3 Codeforces 232E
Sor:我们考虑在x轴二分一个mid考虑x1<=mid<=x2的询问
我们只需要找l--mid-1以及mid+1--r的点能到mid上那些点,
用set存下即可,最后只需判断f[x1][y1]与g[x2][y2]是否存在
交集即可,f和g数组可以利用dp解决,而询问可以利用分治即可
9.4 不会
10 代码:
#include<iostream> #include<algorithm> #include<cstring> #include<cstdio> #include<cmath> #include<bitset> using namespace std; int n,m,k; char s[200000]; int work() { bitset<23000> a, b, c, e; for (int i=0; i<n; i++) { scanf("%s",s); for (int j=0; j<m; j++) { (s[j]=='#'?a:b).set(i*m+j); (s[j]=='E'?e.set(i*m+j):0); } } c=b; scanf("%s",s); for (int i=0; i<k; i++) { if (e==c) return i; if (s[i]=='U') c=((c>>m)&b) | (c&(a<<m)); if (s[i]=='D') c=((c<<m)&b) | (c&(a>>m)); if (s[i]=='L') c=((c>>1)&b) | (c&(a<<1)); if (s[i]=='R') c=((c<<1)&b) | (c&(a>>1)); } if (e==c) return k; return -1; } int main() { while (scanf("%d%d%d",&n,&m,&k)!=EOF) { printf("%d\n",work()); } return 0; }