(bit)是度量信息的单位,包含(0)和(1)两种状态。计算机的各种运算最后无不归结为一个个(bit)的变化。熟练掌握并利用位运算,能够帮助我们理解程序运行中的种种表现,提高程序运行时的时空效率,降低编程时间复杂度。
——选自《算法进阶指南》
而如此功能的位运算,常见的无非也就六种:
1. 与(&) 2.或(|) 3.非(~)
4.异或(^) 5.左移(<<) 6.右移(>>)
至于功能,大家都很熟了,就不再赘述。
OK,位运算讲解结束,全篇完!
还是来讲讲例题吧,不然毫无感觉。。。
一句话题意:求一个序列区间中所有子区间异或和的异或和。
好像有点拗口?就是说:
一区间为(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;
}
再来一道绝世好题咋样???
还是一句话题意:求一段长度为(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~