技巧专题1(二分、三分、位运算)

二分

二分答案一般有以下的一些特征:

A. 候选答案在区间[min,max]上按照某种属性有序,一般枚举复杂度较高。

B. 容易判断某个点是否为可行

 

最大值最小。

判断一个东西是否在一个有序集合中出现或查找位置。

优化搜索,利于搜索剪枝。

二分+ 最短路、并查集、搜索。。。。

 

边界、精度

 

奶牛晒衣服

在熊大妈英明的带领下,时针和它的同伴生下了许多牛宝宝。熊大妈决定给每个宝宝都穿上可爱的婴儿装。于是,为牛宝宝洗晒衣服就成了很不爽的事情。

洗完衣服后,你就要弄干衣服。衣服在自然条件下用1的时间可以晒干A点湿度。抠门的熊大妈买了1台烘衣机。使用烘衣机可以让你用 1的时间使1件衣服除开自然晒干的A点湿度外,还可烘干B点湿度,但在1的时间内只能对1件衣服使用。

N件的衣服因为种种原因而不一样湿,现在告诉你每件衣服的湿度,要你求出弄干所有衣服的最少时间(湿度为0为干)。

$ n \leq 5e5 $

 

文明的复兴

如果把一个单词中的除字母之外符号去掉以后的单词是一个敏感词,那就要屏蔽。这个单词必须要跟一个敏感词完全一样才可以

例如:敏感词sex为不良信息时sex8,sex$,se#x均为不良信息,sexx则不属于不良信息

$ k \leq 1000 , len \leq 1e5 $

 

codevs 1069 关押罪犯

S 城现有两座监狱,一共关押着N 名罪犯,编号分别为1~N。他们之间的关系自然也极不和谐。很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突。我们用“怨气值”(一个正整数值)来表示某两名罪犯之间的仇恨程度,怨气值越大,则这两名罪犯之间的积怨越多。如果两名怨气值为c 的罪犯被关押在同一监狱,他们俩之间会发生摩擦,并造成影响力为c 的冲突事件。

每年年末,警察局会将本年内监狱中的所有冲突事件按影响力从大到小排成一个列表,然后上报到S 城Z 市长那里。公务繁忙的Z 市长只会去看列表中的第一个事件的影响力,如果影响很坏,他就会考虑撤换警察局长。在详细考察了N 名罪犯间的矛盾关系后,警察局长觉得压力巨大。他准备将罪犯们在两座监狱内重新分配,以求产生的冲突事件影响力都较小,从而保住自己的乌纱帽。假设只要处于同一监狱内的某两个罪犯间有仇恨,那么他们一定会在每年的某个时候发生摩擦。那么,应如何分配罪犯,才能使Z 市长看到的那个冲突事件的影响力最小?这个最小值是少?

$ N \leq 20000  ,  M \leq 100000 $

 

软件下载

    ICG大赛马上就要举行了,作为大赛的组委会兼参赛选手,信息组的成员们当然要做准备了,而其中十分重要的一项准备工作就是下载很多举办大赛必不可少的软件,已知现在机房有N台电脑,组委会列出了M个需要下载的软件及其大小Ai(即需要下载的时间),每个电脑同一时间只能下载一个软件,一个软件也只能由一个电脑下载,每个电脑下载速度相同且互不影响

因为有神器Cena的存在,每个软件只需由某一台电脑下载一次就能使整个机房的电脑普及该软件。现在ICG组委会想知道最快能在多长时间内下载完成。

$ M \leq 50 , N \leq 10$

二分+搜索剪枝
相当于把个数分成N份
dis(x,y,z,mid),表示分了x份,共用了y个数,总共还剩下z的时间,并且当前的二分中点为mid
一份一份搜索(枚举每一份可以装什么)
加上减枝(维护剩下的所有空间,是否还可能装下剩下所有物品)
因为它不用完全遍历,所以实际上的时间复杂度较低。

 

  

 

电话网络

由于地震使得连接汶川县城的电话线全部损坏,假如你是负责将电话线接到震中汶川县城的负责人,汶川县城周围分布着 N ( 1 ≤ N ≤ 1000 )根按 1..N 顺次编号的废弃的电话线杆去,任意两根电话线杆间都没有电话线相连。一共 P(1 ≤ P ≤ 10000) 对电话线杆间可以拉电话线,其余的由于地震使得无法被连接。

第 i 对电话线杆的两个端点分别为 Ai , Bi ,它们间的距离为 Li ( 1 ≤ Li ≤ 1000000 )。数据保证每对( Ai,Bi )最多只出现 1 次。编号为 1 的电话线杆已经接入了全国的电话网络,整个县城的电话线全都连到了编号为 N 的电话线杆上。

也就是说,你的任务仅仅是找一条将 1 号和 N 号电话线杆连起来的路径,其余电话线杆并不一定要连入电话网络。

电信公司决定支援灾区免费为汶川县城连接 K ( 0 ≤ K < N )对由你指定的电话线杆。对于此外的那些电话线,需要为它们付费,总费用等于其中最长的电话线的长度(每根电话线仅连接一对电话线杆)。如果需要连接的电话线杆不超过 K 对,那么总支出为 0 。

请你计算一下,将电话线引到震中汶川县城最少需要在电话线上花多少钱?

 

 

ricehub

沿着米道上 R 块稻田,每块稻田的坐标均为一个 1 到 L 之间(含 1 和 L)的整数。
即对于 0 ≤ i <R,稻田 i 的坐标 X[i]满足 1 ≤ X[0] ≤ ... ≤ X[R-1] ≤ L。 
注意:可能有多块稻田位于同一个坐标上。 
我们计划建造一个米仓用于储存尽可能多的稻米。米仓将建在米道上,其坐标也是一个 1 到 L 之间的整数(含 1 和 L)。
将稻米从特定的稻田运到米仓的费用在数值上等于稻田坐标与米仓坐标之差的绝对值。
我们至多只能花费 B 元运费。你的任务是要帮我们找出一个建造米仓的位置,可以收集到尽可能多的稻米。 
$ 1 \leq R \leq 1e5 , 1 \leq L \leq 1e9 , 0 \leq B \leq 2e15 $

 

 

Well

给定一个非负整数序列A,每次操作可以选择一个数然后减掉1,要求进行不超过m次操作使得存在一个Ak=0且$max(abs(Ai−A_{i+1}))$最小,输出这个最小值以及此时最小的k

二分答案,然后验证的时候首先让相邻的都不超过x,然后枚举哪个点应该改成0
如果某个点需要改成0,那么需要进行操作的位置是一段区间,左右端点都单调,扫两遍就行了。
bool Judge(long long limit)
{
    long long cost=0;
    int i,j;
    static int b[M];
    for(i=1;i<=n;i++) b[i]=a[i];
    for(i=2;i<=n;i++) if(b[i]-b[i-1]>limit)
    {
        cost+=b[i]-b[i-1]-limit;
        b[i]=b[i-1]+limit;
    }
    for(i=n-1;i;i--) if(b[i]-b[i+1]>limit)
    {
        cost+=b[i]-b[i+1]-limit;
        b[i]=b[i+1]+limit;
    }
    if(cost>m) return false;
    static long long sum[M];
    for(i=1;i<=n;i++) sum[i]=sum[i-1]+b[i];
    static int l[M],r[M];
    for(j=1,i=1;i<=n;i++)
    {
        while( b[j]<(long long)(i-j)*limit ) j++;
        l[i]=j;
    }
    for(j=n,i=n;i;i--)
    {
        while( b[j]<(long long)(j-i)*limit ) j--;
        r[i]=j;
    }
    for(i=1;i<=n;i++)
    {
        long long _cost=(sum[r[i]]-sum[l[i]-1]);
        _cost-=(long long)limit*(i-l[i])*(i-l[i]+1)>>1;
        _cost-=(long long)limit*(r[i]-i)*(r[i]-i+1)>>1;
        if(cost+_cost<=m)
            return pos=i,true;
    }
    return false;
}

 

三分

三分算法解决凸形或者凹形函数的极值。

如图所示,已知左右端点L、R,要求找到白点的位置。

思路:通过不断缩小 [L,R] 的范围,无限逼近白点。

做法:先取 [L,R] 的中点 mid,再取 [mid,R] 的中点 mmid,通过比较 f(mid) 与 f(mmid) 的大小来缩小范围。

           当最后 L=R-1 时,再比较下这两个点的值,我们就找到了答案。

1、当 f(mid) > f(mmid) 的时候,我们可以断定 mmid 一定在白点的右边。

反证法:假设 mmid 在白点的左边,则 mid 也一定在白点的左边,又由 f(mid) > f(mmid) 可推出 mmid < mid,与已知矛盾,故假设不成立。

所以,此时可以将 R = mmid 来缩小范围。

2、当 f(mid) < f(mmid) 的时候,我们可以断定 mid 一定在白点的左边。

反证法:假设 mid 在白点的右边,则 mmid 也一定在白点的右边,又由 f(mid) < f(mmid) 可推出 mid > mmid,与已知矛盾,故假设不成立。

同理,此时可以将 L = mid 来缩小范围。

好记一点就是:我们把当前区间分成3个区间,分界点分别是mid和midd。f(mid)和f(midd)哪个更小就把最那边的一个区间去掉不要,中间的那个区间一定会保留下来。

算法的正确性:

1、mid与midmid在最值的同一侧。由于凸性函数在最大值(最小值)任意一侧都具有单调性,因此,mid与midmid中,更大(小)的那个 数自然更为靠近最值。此时,我们远离最值的那个区间不可能包含最值,因此可以舍弃。
2、mid与midmid在最值的两侧。由于最值在中间的一个区间,因此我们舍弃一个区间后,并不会影响到最值

题目:

HDU :3400  2298  4454  2438  3756 

POJ:  3301   3737  

ZOJ: 3203

 

经常需要浮点数,一般eps较小,1e-12左右。

因为需要证明是单峰函数,所以经常和数学、计算几何相关,需要推式子、求导一类的。

 

Light Bulb

给出灯离地面高度H,人的身高h,灯跟墙的距离D,人站在不同位置,影子的长度都不一样,求出最长的影子的长度。

 

 

Texas Trip

给出n个点的坐标,现在要求一个正方形,完全包围n个点,并且正方形面积最小,求最小的正方形面积。

1)想到求覆盖所有点,那么可以枚举任意两点之间的距离,并求出其中最大距离,作为正方形的边;
按照以上想法来求解当然可以求解出一个能够覆盖所有点的正方形,但是不能保证其是最小的
假设在我们求出的最小正方形s中,其中两点p1,p2正好落在对角线的两个端点上,
那么在p1和p2之间的距离正是想法1中所求出的最大长度,
按照想法1去求解的话,所求出的正方形s'一定比s的面积大;
2)进一步思考的话,之所以出现假设与想法1之间矛盾的原因在于:
想法1求解的方式只考虑了两点之间的直线距离,
但是在二维空间下,覆盖所有点的最小正方形应该由“x方向距离”和“y方向之间距离”的同时来决定的,
而能够影响这两个坐标轴距离长短的因素就在于我们如何将这些点投影到二维坐标系中;
3)将n各点投影到二维坐标系中,我们可以以任意点为基点,对所有点进行旋转
考虑到我们主要求解的是最小面积,则在[0,180]与[180,360]之间可以看做是对称的
由此将整个问题转换成将所有点投影到二维坐标系中,枚举角度的问题,具体的枚举方式用三分法。
单峰函数的求证涉及数学内容(二阶导数),坐标转换(即坐标系旋转)涉及计算几何内容。。。。

 

 

UmBasketella 

给出一个圆锥体的表面积(底面积+侧面积)。让你求出这个圆锥的最大体积和此时的高与半径。 

根据题目意思,我们可以得出有两个变量还有一个条件,
那么我们可以利用这个条件来减少一个变量,最后再利用函数的性质来求得最大值。
S=PI* r* sqrt(h* h+r* r)+PI* r* r ; V=PI* r* r* h/3 。
我们去掉S中的开根号化简,可以得到r* r=S* S/(PI* PI* h* h+2* PI* S).
然后把r* r带入V中,化简得到V=(S* S/3)/Tmp, Tmp=PI* h+2* S/h,
当PI* h=2* S/h时,Tmp取得最小值2* sqrt(2* S* PI), 
这个时候V=(S* S/3)/Tmp, h=sqrt(2* S/PI), r=sqrt(3* V/(PI* h))。

 

 

位运算

比较常用的几个功能:

乘除法:<< >>

判断奇偶性:a&1

交换两个数:a^=b^=a^=b;(a^=b,b^=a,a^=b)

判断两个数是否相同:a^b==0

lowbit : x&(-x)

判断n是否是2的整数冪:x==(x&(-x))

枚举子集:for(int i=x;i;) i=(i-1)&x; 

 

 

统计二进制中1的个数:

朴素的统计办法是比较简单的,每次用x=(x&(x-1))将最后一个1翻转,直接计数就好了

int count1Bits(long n)  
{  
    int count =0;  
    while(n)  
    {  
        count++;  
       n&=(n-1);  
    }  
    return count;  
}  

下面我们来看看比较高级的办法。

 考虑2位整数 n=11(十进制为3),里边有2个1,先提取里边的偶数位10,奇数位01,把偶数位右移1位,然后与奇数位相加,因为每对奇偶位相加的和不会超过“两位”,所以结果中每两位保存着数n中1的个数,那么把 n 计算之后得到的值为:

(10>>1)+01 = 01 + 01 = 10, 把10换成十进制就是 2,2就代表 n(3)=11 中有两个1!

相应的如果n是四位整数 n=0111(十进制7),先以“一位”为单位做奇偶位提取:偶数位 0010,奇数位0101。然后偶数位移位(右移1位)再相加:(0010>>1)+0101=0110;再用0110以“两位”为单位做奇偶提取:偶数为0100,奇数位0010。偶数位移位(这时就需要移2位)再相加:(0100>>2)+0010=0011,因为此时每对奇偶位的和不会超过“四位”,所以结果中保存着n中1的个数:(0100>>2)+0010=0011 把0011换成十进制就是3,3就是n(7)=0111中有3个1。

依次类推可以得出更多位n的算法。整个思想类似分治法。

int CountOne(unsigned int n)  
{  
    //0xAAAAAAAA,0x55555555分别是以“1位”为单位提取奇偶位  
    n = ((n & 0xAAAAAAAA) >> 1) + (n & 0x55555555);  
    //0xCCCCCCCC,0x33333333分别是以“2位”为单位提取奇偶位  
    n = ((n & 0xCCCCCCCC) >> 2) + (n & 0x33333333);  
    //0xF0F0F0F0,0x0F0F0F0F分别是以“4位”为单位提取奇偶位  
    n = ((n & 0xF0F0F0F0) >> 4) + (n & 0x0F0F0F0F);  
    //0xFF00FF00,0x00FF00FF分别是以“8位”为单位提取奇偶位  
    n = ((n & 0xFF00FF00) >> 8) + (n & 0x00FF00FF);  
    //0xFFFF0000,0x0000FFFF分别是以“16位”为单位提取奇偶位  
    n = ((n & 0xFFFF0000) >> 16) + (n & 0x0000FFFF);  
  
    return n;  
}  

  

常用的二进制数:

二进制数 二进制值 用处
0xAAAAAAAA 10101010101010101010101010101010 偶数位为1,以1位为单位提取奇位
0x55555555 01010101010101010101010101010101 奇数位为1,以1位为单位提取偶位
0xCCCCCCCC 11001100110011001100110011001100 以“2位”为单位提取奇位
0x33333333 00110011001100110011001100110011 以“2位”为单位提取偶位
0xF0F0F0F0 11110000111100001111000011110000 以“8位”为单位提取奇位
0x0F0F0F0F 00001111000011110000111100001111 以“8位”为单位提取偶位
0xFFFF0000 11111111111111110000000000000000 以“16位”为单位提取奇位
0x0000FFFF 00000000000000001111111111111111 以“16位”为单位提取偶位

 

 

 

 

 

 

 

 

 

1.    将最右侧的1翻转成0:x&(x-1)

假设x=01110100,那么x,x-1和x&(x-1)的二进制表示分别如下:

x:

0

1

1

1

0

1

0

0

x-1:

0

1

1

1

0

0

1

1

X&(x-1):

0

1

1

1

0

0

0

0

 

 

 

 

 

可以看出,x-1的功能是:将最右侧的1翻转了,并让其后的0变成了1,而保持了其他位不变。然后x&(x-1)就使得x的最右侧的1翻转成0。

该位运算在上一篇中被用来计算二进制中有多少个1,其思路是:不停的翻转右侧的1,知道将该数翻转成0为止。

2.       向右连续传播最右侧的1位:x|(x-1)

比如说x=00101000,那么x,x-1和x|(x-1)的二进制表示分别如下:

x:

0

0

1

0

1

0

0

0

x-1:

0

0

1

0

0

1

1

1

X|(x-1):

0

0

1

0

1

1

1

1

 

 

 

  

 

从上面的过程可以看出x|(x-1)使得x中最右边的1的右边的0都被1填充了,注意这不能理解成:翻转最右侧的连续的0,而应该理解成用最右侧的1填充了它右边的所有0位。或许你要问为什么,那么你假设x =00101001,那么x|(x-1)仍然等于00101001,它并没有将最右侧的两个0翻转!

3.       检查无符号数x是否是2的整数次幂:if((x&(x-1))==0)return true;

由1可知:x&(x-1)的作用是将最右侧的1翻转为0,假如翻转之后结果变成了0,则说明原来的数x的二进制表示中只包含一个1,那么它必定是2的整数次幂。这个简单,我就不图示了。记住:2的整数次幂2的整数次幂减1进行与运算的结果必然为0。

4.       检查无符号数x是否等于2的整数次幂减1:if((x&(x+1))==0) return true;

2的整数次幂减1再加1之后就等于2的整数次幂,于是可以用3的方法来判断,这也非常简单,不再图示。

5.       将右侧的连续1位串翻转成0位串,其他保持不变:((x|(x-1))+1)&x

比如x等于00101100,那么

x:

0

0

1

0

1

1

0

0

x-1:

0

0

1

0

1

0

1

1

X|(x-1):

0

0

1

0

1

1

1

1

(X|(x-1))+1

0

0

1

1

0

0

0

0

((X|(x-1))+1)&x

0

0

1

0

0

0

0

0

 

 

 

 

 

 

 

 

由2得知:x|(x-1) 使得x中最右边的1的右边的0都被1填充了;而(x|(x-1))+1 就使得x中那个连续的1位串和它右边的0位串都变成0,并且将连续的1位串的左边那位0变成了1,并保持其他位不变; (x|(x-1)+1)&x使得x中那个连续的1位串和它右边的所有位都置为0,而保持那个连续的1位串的左边保持不变,于是就实现了将最右边的连续的1位串翻转的功能。

文字解释绕来绕去的,非常拗口啊,没办法啊,这个关系本省就绕,希望不会把各位绕糊涂了。

6.       检查无符号整数x是否等于2的两个整数次幂之差:                                                                                                                   if((((x|(x-1))+1)&x)==0)==0) return true;

所谓2的两个整数次幂之差就是2k-2j,比如k等于6,j等于2,那么26的二进制是:01000000,22的二进制表示为00000100,26-22的二进制表示为00111100,由此可以看出2k-2j的特征是:二进制表示形式中从第j位到第k-1位都是1(从0开始数),其他bit位都是0

由上可知:通过位运算在保持其他bit位不被改变的情况下,将这些为1的bit位全部翻转为0,如果所得的结果等于0,那么原来的数就是一定是2的两个整数次幂之差!事实上5中已经介绍了((x|(x-1))+1)&x的功能就是将x的二进制表示中右侧连续的1位串翻转为0位串,因此只需要应用3计算((X|(x-1))+1)&x的值,然后判断它是否等于0即可,为了说明这个问题,我再图示演示了这一过程,这里的x等于00111100

x:

0

0

1

1

1

1

0

0

x-1:

0

0

1

1

1

0

1

1

X|(x-1):

0

0

1

1

1

1

1

1

(X|(x-1))+1

0

1

0

0

0

0

0

0

((X|(x-1))+1)&x

0

0

0

0

0

0

0

0

 

 

 

 

 

 

 

 

从上表看出,由于最后计算结果等于0,所以x就是两个2的整数次幂的差,其实x = 60 = 26-22。

位运算求组合:http://blog.csdn.net/w57w57w57/article/details/6657547 

 

 

负数的二进制是其正值的补码。

 

 

数数字

给你一个整数数列,保证只有一个数出现过奇数次,输出它。

$ 1 \leq n \leq 5e5 , -1e6 \leq ai \leq 1e6 $

 

数数字2

输入一些数字,int范围内,大部分数字都出现了三次,只有一个数字出现了一次,输出这个数字。

用ones代表只出现一次的数位,twos代表出现了两次的数位,xthrees代表出现了三次的数位。
 public int singleNumber(int[] A) {
        int ones=0;
        int twos=0;
        int xthrees=0;
        for(int i = 0;i <A.length;i++){
                twos ^= (ones&A[i]);
                ones ^= A[i];
                xthrees = ~(ones&twos);
                twos &= xthrees;
                ones &= xthrees;
         }
         return ones;
  }
遍历结束后,ones即为所求。

 

  

 

树上路径异或和

有一个树形图,每条边有一个边权,问路径上权值异或结果为s 的路有多少个

$1 \leq T \leq 25 , 1 \leq  N \leq 10^5 $

 

 

最大异或和

给定一个非负整数序列 {a},初始长度为 N。有   M个操作,有以下两种操作类型:

1 、A x:添加操作,表示在序列末尾添加一个数 x,序列的长度 N+1。
2 、Q l r x:询问操作,你需要找到一个位置 p,满足 l<=p<=r,使得:
a[p] xor a[p+1] xor … xor a[N] xor x 最大,输出最大是多少。

$N,M \leq 300000 , 0 \leq a[i] \leq 1e7$

 

GCD XOR

求gcd(a, b) = a ^ b且满足1 <= b <= a <= N的(a, b)对数

$N \leq 3e7$

证明gcd( a , b ) == a xor b 时,gcd( a , b ) == a xor b == a - b
它是根据 gcd( a , b ) <= a - b <= a xor b 得来的。

 

绝世好题

给定一个序列a,求一个子序列b使得bi and bi−1≠0且|b|最大

按照每一位来进行dp
f[i]表示最后一个数的第i个二进制为1的最长子序列个数 
每次转移时把a[i]拆成二进制位,然后取数为1的位上f最大值就可以了

 

二进制a+b

输入三个整数a, b, c,把它们写成无前导0的二进制整数。比如a=7, b=6, c=9,写成二进制为a=111, b=110, c=1001。

接下来以位数最多的为基准,其他整数在前面添加前导0,使得a, b, c拥有相同的位数。比如在刚才的例子中,添加完前导0后为a=0111, b=0110, c=1001。

最后,把a, b, c的各位进行重排,得到a’, b’, c’,使得a’+b’=c’。比如在刚才的例子中,可以这样重排:a’=0111, b’=0011, c’=1010。

你的任务是让c’最小。如果无解,输出-1。

法1:dp

法2:神奇的做法(http://blog.csdn.net/lych_cys/article/details/51088803)

int calc(int x){ int t=0; for (; x; x>>=1) t++; return t; }
int getit(int x){ int t=0; for (; x; x^=x&-x) t++; return t; }
int main(){
  int a,b,c; scanf("%d%d%d",&a,&b,&c);
  int len=max(max(calc(a),calc(b)),calc(c)),ans;
  a=getit(a); b=getit(b); c=getit(c);
  if (a>b) swap(a,b);
  if (c<=a) ans=(1<<(a+b-c))|((1<<c)-2);
  else if (c<=b) ans=((1<<b)|((1<<c)-1))^(1<<(c-a));
  else if (c<=a+b) ans=((1<<(c+1))-1)^(1<<(c+c-a-b));
  else{ puts("-1"); return 0; }
  printf("%d\n",(calc(ans)<=len)?ans:-1);
  return 0;
}

 

线性基

若干数的线性基是一组数a1,a2...an,其中ax最高位在x位

通过线性基中元素xor出的数的值域与原来的数xor出数的值域相同。

构造:对每一个数p从高位到低位扫,扫到第x位为1时,若ax不存在,则ax=p并结束此数的扫描,否则令p =p xor ax。

查询能被xor出的最大值:从高往低扫ax,若异或上ax使答案变大,则异或。

判断一个数能否被xor出:从高到低,对该数每个是1的位置x,将这个数异或上ax(注意异或后这个数为1的位置和原数就不一样了),若最终变为0,则可被异或出。需要特判0(在构造过程中看是否有p变为0即可)。

 

很多情况下,只有有关异或运算和求最值,就可以用到线性基。

线性基有很多很好的性质,比如说如果有很多个数,我们可以构出这些数的线性基,那么这个线性基可以通过互相xor,能够构出原来的数可以相互xor构出的所有的数。所以可以大大减少判断的时间和次数。

线性基的任何一个非空子集都不会使得其xor和为0

 

再见XOR

给定N个数,你可以在这些数中任意选一些数出来,每个数可以选任意多次,试求出你能选出的数的异或和的最大值和严格次大值。

$N \leq 1e5$

 

XOR

给定一个数组,求这些数组通过异或能得到的数中的第k小是多少。

$N \leq 1e4$

我们要将线性基改造。具体操作就是如果i<j,aj的第i位是1,就将aj异或上ai。
所以查询的时候将k二进制拆分,对于1的位,就异或上对应的线性基。
最终得出的答案就是k小值。
void rebuild()
{
    for (int i=60;i>=0;i--)
        for (int j=i-1;j>=0;j--)
            if (d[i]&(1LL<<j))
                d[i]^=d[j];
    for (int i=0;i<=60;i++)
        if (d[i])
            p[cnt++]=d[i];
}
long long kthquery(long long k)
{
    int ret=0;
    if (k>=(1LL<<cnt))
        return -1;
    for (int i=60;i>=0;i--)
        if (k&(1LL<<i))
            ret^=p[i];
    return ret;
}

 

元素

n个二元组(a,b),求一个$ \sum b$最大,且a的所有子集异或和不为0

$n \leq 1000$

贪心,按照b从大到小排序,动态维护线性基。

  

 

[wc2011]Xor

存在重边且允许经过重复点、重复边

$N \leq 5e4 , M \leq 2e5$

这道题要求从1到n的最大xor和路径。
那么在图上作图尝试之后就会发现,路径一定是由许多的环和一条从1到n的路径组成。
容易发现,来回走是没有任何意义的,因为来回走意味着抵消。
考虑这道题求得是路径xor和最大,所以必然我们要想办法处理环的情况。
任意地先找出一条从1到n的路径,把这条路径上的xor和作为ans初值,
然后我们的任务就变成了求若干个环与这个ans初值所能组合成的xor最大值。
显然,我们需要预处理出图上所有的环,并处理出所有环的环上xor值,
这当然是dfs寻找,到n的路径的时候顺便求一下就可以了。
当我们得到了若干个环的xor值之后,因为是要求xor最大值,我们就可以构出这所有xor值的线性基。
构出之后,再用ans在线性基上取max就可以了。

 

  

 

 

CF724G

1e5个点的无向图,三元组(u,v,s),u<v,满足u经过路径到达v,把路径上经过的边的值求异或和等于s。三元组的价值为s。求所有三元组的总价值之和。

 

 

参考资料:

https://wenku.baidu.com/view/7ce63dda680203d8ce2f2451.html

http://blog.sina.com.cn/s/blog_9aa2786a0101biz1.html

http://blog.sina.com.cn/s/blog_7e050dc80102wj5r.html

http://blog.csdn.net/PoPoQQQ/article/details/46412233

http://blog.csdn.net/pi9nc/article/details/9666627

http://blog.csdn.net/controlbear/article/details/54237388

http://blog.csdn.net/flushhip/article/details/50963942

http://blog.csdn.net/loverooney/article/details/24592641

http://www.360doc.com/content/12/0801/17/6828497_227700914.shtml

http://blog.csdn.net/jerans/article/details/53198761

http://blog.csdn.net/yunyu5120/article/details/6692072

http://blog.csdn.net/w57w57w57/article/details/6634654

http://blog.csdn.net/w57w57w57/article/details/6638298

http://blog.csdn.net/w57w57w57/article/details/6657547

http://blog.csdn.net/xym_CSDN/article/details/52301891

http://blog.csdn.net/lych_cys/article/details/51088803

http://www.cnblogs.com/ljh2000-jump/p/5869991.html

http://www.cnblogs.com/chty/tag/%E7%BA%BF%E6%80%A7%E5%9F%BA/

http://blog.csdn.net/gjghfd/article/details/74745309

posted @ 2017-12-04 10:13  shixinyi  阅读(709)  评论(0编辑  收藏  举报