回归本源--位运算及其应用

序:这篇论文起初第一眼看的时候觉得没什么用处,后来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
",work());
    }
    return 0;
}
97D
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<bitset>
#include<vector>
#define pb push_back
#define N 505
using namespace std;
int n,m,k;
char a[N][N];
struct data{
    int id,x1,x2,y1,y2;
}q;
typedef vector<data> V;
bitset<N> f[N][N],g[N][N];
V v;
bool ans[600005];
int read()
{
    int x=0,f=1; char ch;
    while (ch=getchar(),ch<'0'||ch>'9') if (ch=='-') f=-1;
    while (x=x*10+ch-'0',ch=getchar(),ch>='0'&&ch<='9');
    return x*f;
}
void solve(int l,int r,V v)
{
    if (l>r) return ; 
    int mid=(l+r)>>1;
    for (int i=mid; i>=l; i--)
        for (int j=m; j>=1; j--){
            f[i][j]=0;
            if (a[i][j]=='.'){
                if (i==mid) f[i][j][j]=1;
                else f[i][j]|=f[i+1][j];
                if (j!=m) f[i][j]|=f[i][j+1];
            }
        }
    for (int i=mid; i<=r; i++)
        for (int j=1; j<=m; j++){
            g[i][j]=0;
            if (a[i][j]=='.'){
                if (i==mid) g[i][j][j]=1;
                else g[i][j]|=g[i-1][j];
                if (j!=1) g[i][j]|=g[i][j-1];
            }
        }
    V v1,v2;
    for (V::iterator it=v.begin(); it!=v.end(); it++){
        q=*it;
        if (q.x2<mid) v1.pb(q);
        else if (q.x1>mid) v2.pb(q);
        else ans[q.id]=(f[q.x1][q.y1]&g[q.x2][q.y2]).any();
    }
    solve(l,mid-1,v1); solve(mid+1,r,v2);
}
int main()
{
    n=read(); m=read(); for (int i=1; i<=n; i++) scanf("%s",a[i]+1);
    k=read();
    for (int i=1; i<=k; i++) {
        q.id=i; q.x1=read(),q.y1=read(),q.x2=read(),q.y2=read();
        v.pb(q);
    }
    solve(1,n,v);
    for (int i=1; i<=k; i++) if (ans[i]) printf("Yes
"); else printf("No
");
    return 0;
}
232E

  

原文地址:https://www.cnblogs.com/HQHQ/p/5996259.html