zoukankan      html  css  js  c++  java
  • 位运算


    (bit)是度量信息的单位,包含(0)(1)两种状态。计算机的各种运算最后无不归结为一个个(bit)的变化。熟练掌握并利用位运算,能够帮助我们理解程序运行中的种种表现,提高程序运行时的时空效率,降低编程时间复杂度。

    ——选自《算法进阶指南》


    而如此功能的位运算,常见的无非也就六种:

    1. 与(&) 2.或(|) 3.非(~)

    4.异或(^) 5.左移(<<) 6.右移(>>)

    至于功能,大家都很熟了,就不再赘述。

    OK,位运算讲解结束,全篇完!


    还是来讲讲例题吧,不然毫无感觉。。。


    例题1:P6225 异或橙子

    一句话题意:求一个序列区间中所有子区间异或和的异或和。

    好像有点拗口?就是说:

    一区间为(a_1)~(a_3),

    (ans~=~a_1~xor~a_2~xor~a_3~xor~(a_1~xor~a_2)~xor~(a_2~xor~a_3)~xor~(a_1~xor~a_2~xor~a_3))

    第一眼看过去,就三个字:不可做!但我仔细看了看,有一个惊人发现:我还是不会。

    没办法,找找规律试试:

    1.区间为(a_1)~(a_3Rightarrow~ans=a_1~xor~a_3)

    2.区间为(a_1)~(a_4Rightarrow~ans=0)

    3.区间为(a_1)~(a_5Rightarrow~ans=a_1~xor~a_3~xor~a_5)

    4.区间为(a_1)~(a_6Rightarrow~ans=0)

    突然我又有了惊人的发现:区间长度为偶数时答案为(0),区间长度为奇数时答案为所有下标为奇数的权值的异或和!

    然后现实又给了我一巴掌:

    5.区间为(a_2)~(a_7Rightarrow~ans=a_2~xor~a_4~xor~a_6)

    这次错不了,答案为区间内所有与端点下标奇偶性相同的权值的异或和。(端点不同则答案为(0)

    有了这个性质,我们就可以用两颗线段树或树状数组,保存奇数和偶数的异或和,进行查询和修改

    然后。。没有然后了。。。

    呸,然后手起,码落:

    #include<bits/stdc++.h>
    #define re register
    #define lowbit(x) ((x)&(-x))
    using namespace std;
    const int N=200005;
    int n,m,a[N],val[N][2];
    inline void add(int x,int y,bool yor)
    {
    	for(;x<=n;x+=lowbit(x))
    		val[x][yor]^=y;
    }
    inline int ask(int x,bool yor)
    {
    	re int sum=0;
    	for(;x>0;x-=lowbit(x))
    		sum^=val[x][yor];
    	return sum;
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for(re int i=1;i<=n;i++)scanf("%d",&a[i]),add(i,a[i],i&1);
    	for(re int type,l,r;m--;)
    	{
    		scanf("%d%d%d",&type,&l,&r);
    		if(type==1)	add(l,a[l],l&1),add(l,r,l&1),a[l]=r;
    		else printf("%d
    ",((r-l+1)&1)?ask(r,r&1)^ask(l-2,l&1):0);
    	}
    	return 0;
    }
    

    再来一道绝世好题咋样???

    例题2:P4310 绝世好题

    还是一句话题意:求一段长度为(n)区间的最长子区间长度,使其满足(a_i~&~a_{i+1}!=0)

    有没有感觉似曾相识?好像最长上升子序列是变成了最长“与后非零”子序列。

    (nle10^5),没法与最长上升子序列一样(O(n^2))求答案,还是毫无头绪。。

    不对,曾记否?学长说过,它(O(nlogn))也能求!

    但蒟蒻的我从未打过(O(nlogn))求最长上升子序列。。

    慢着,等我去学学再来。

    所以各位读者:休息一下,马上回来!

    OK,咱们继续,

    (O(nlogn))的最长上升子序列与之前不同,保存的不是(a_i)最大能排在第几位,而是排在第(i)位的数最小可以为多少。

    那我们依葫芦画瓢,保存。。(额,还是不会

    突然想起来这章讲的是位运算!与的运算法则又是同一为一,其余为零,那我们保存子序列最后一项二进制下第(i)位为(1)的最大长度,然后转移方程就出来了:

    (f_j=max{f_j}+1(0le jle 32))((a_i)在二进制下第(j)位为(1))

    然后我们就A了一道绝世好题。。

    手起,码落:

    #include<bits/stdc++.h>
    #define re register
    using namespace std;
    int n,a,f[40],ans;
    int main()
    {
    	scanf("%d",&n);
    	for(re int i=1,maxx;i<=n;i++)
    	{
    		scanf("%d",&a);maxx=0;
    		for(re int j=0;j<=32;j++)
    			if((a>>j)&1)maxx=max(maxx,f[j]+1);
    		for(re int j=0;j<=32;j++)
    			if((a>>j)&1)f[j]=maxx;
    	}
    	for(re int i=0;i<=32;i++)ans=max(f[i],ans);
    	printf("%d",ans);
    	return 0;
    }
    

    讲完了,不容易呀,给个赞在走不,QWQ~

  • 相关阅读:
    java的异常
    Quartz使用总结
    MYSQL性能优化的最佳20+条经验
    索引原理和慢查询优化
    MySQL索引背后的数据结构及算法原理
    常见电商项目的数据库表设计(MySQL版)
    常见试题和算法
    mysql性能调优与架构设计笔记
    MYSQL数据库设计规范与原则
    复合索引的优点和注意事项
  • 原文地址:https://www.cnblogs.com/jkzcr01-QAQ/p/13575197.html
Copyright © 2011-2022 走看看