【HDU3949】XOR 线性基

#include <stdio.h>
int main()
{
	puts("转载请注明出处谢谢");
	puts("http://blog.csdn.net/vmurder/article/details/43448493");
}

题意:给若干个数让你异或,然后询问第k大的异或和。

题解:

先搞出来线性基,然后第k大的异或和就是:

把k二进制拆分,第i位上有1,就把第i个线性基异或进来。

原因:

因为线性基是一堆高位上的1(或许有一些位动不了),然后把这样每一位可以填0/1,跟二进制差不多。

自己脑补去吧。

……我在说什么啊,我明白但是懒得写了。别管了,扒代码或者留言神马的吧。

经验之谈:

最开始写的是这份代码(WA):

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 10100
using namespace std;
int n,m;
unsigned long long a[N],ins[70];
bool flag;
void EX_Ins(int n)
{
	int i,j,k;
	flag=0;
	memset(ins,0,sizeof ins);
	for(i=n;i;i--)
	{
		for(j=63;~j;j--)if((a[i]>>j)&1)
		{
			if(!ins[j])
			{
				ins[j]=a[i];
				for(k=63;k>j;k--)
					if((ins[k]>>j)&1)
						ins[k]^=ins[j];
				break;
			}
			else a[i]^=ins[j];
		}
		if(!a[i])flag=1;
	}
	return ;
}
int main()
{
	freopen("test.in","r",stdin);
	int i,g,_g;
	unsigned long long k;
	for(scanf("%d",&_g),g=1;g<=_g;g++)
	{
		printf("Case #%d:\n",g);
		scanf("%d",&n);
		for(i=1;i<=n;i++)scanf("%llu",&a[i]);
		sort(a+1,a+n+1);
		EX_Ins(n);
		for(m=i=0;i<=63;i++)
		{
			if(ins[i])ins[m++]=ins[i];
		}
		for(scanf("%d",&n);n--;)
		{
			scanf("%llu",&k);
			if(flag)k--;
			if(k>>m)puts("-1");
			else {
				unsigned long long ret=0;
				for(i=0;i<m;i++)if((k>>i)&1)
					ret^=ins[i];
				printf("%llu\n",ret);
			}
		}
	}
	return 0;
}

它WA了,请看这组数据:

1
3
77 89 53
1
7

为什么会WA呢?

我维护线性基的方法是先排个序从大到小往里面加,

然后这样出来一个线性基时就再对之前的线性基进行修改、、

然后就WA了。

貌似有理有据,但是错在了哪里呢?

嗯,一个大的数A可能被之前某个线性基异或一下,变成比之后的数更小的数了,

于是它的最高位上有个1,

然后之后某个初始值小的数B成为了线性基,但是它在数A那个线性基的那一位上有1,

然后自然就挂了~~

询问时就会有3<2的情况了(ins[1]^ins[2]<ins[2])

诶,233。

AC代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 10100
using namespace std;
int n,m;
unsigned long long a[N],ins[70];
bool flag;
void EX_Ins(int n)
{
	int i,j,k;
	flag=0;
	memset(ins,0,sizeof ins);
	for(i=n;i;i--)
	{
		for(j=63;~j;j--)if((a[i]>>j)&1)
		{
			if(!ins[j])
			{
				ins[j]=a[i];
				for(k=0;k<63;k++)
					for(int r=k+1;r<=63;r++)
						if((ins[r]>>k)&1)
							ins[r]^=ins[k];
				break;
			}
			else a[i]^=ins[j];
		}
		if(!a[i])flag=1;
	}
	return ;
}
int main()
{
	freopen("test.in","r",stdin);
	int i,g,_g;
	unsigned long long k;
	for(scanf("%d",&_g),g=1;g<=_g;g++)
	{
		printf("Case #%d:\n",g);
		scanf("%d",&n);
		for(i=1;i<=n;i++)scanf("%llu",&a[i]);
	//	sort(a+1,a+n+1);
		EX_Ins(n);
		for(m=i=0;i<=63;i++)
		{
			if(ins[i])ins[m++]=ins[i];
		}
		for(scanf("%d",&n);n--;)
		{
			scanf("%llu",&k);
			if(flag)k--;
			if(k>>m)puts("-1");
			else {
				unsigned long long ret=0;
				for(i=0;i<m;i++)if((k>>i)&1)
					ret^=ins[i];
				printf("%llu\n",ret);
			}
		}
	}
	return 0;
}
时间: 2024-08-23 13:27:25

【HDU3949】XOR 线性基的相关文章

HDU3949 XOR(线性基第k小)

Problem Description XOR is a kind of bit operator, we define that as follow: for two binary base number A and B, let C=A XOR B, then for each bit of C, we can get its value by check the digit of corresponding position in A and B. And for each digit,

[hdu3949]XOR(线性基求xor第k小)

题目大意:求xor所有值的第k小,线性基模板题. #include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> #include<iostream> #include<cmath> using namespace std; typedef long long ll; const int MAX_BASE=63; ll base[64],a[10006]

BZOJ 2115: [Wc2011] Xor 线性基

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2115 解法: 膜:http://www.cnblogs.com/ljh2000-jump/p/5869925.html 这道题要求从1到n的最大xor和路径,存在重边,允许经过重复点.重复边.那么在图上作图尝试之后就会发现,路径一定是由许多的环和一条从1到n的路径组成.容易发现,来回走是没有任何意义的,因为来回走意味着抵消.考虑这道题求得是路径xor和最大,所以必然我们要想办法处理环的情

【BZOJ-2115】Xor 线性基 + DFS

2115: [Wc2011] Xor Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 2142  Solved: 893[Submit][Status][Discuss] Description Input 第一行包含两个整数N和 M, 表示该无向图中点的数目与边的数目. 接下来M 行描述 M 条边,每行三个整数Si,Ti ,Di,表示 Si 与Ti之间存在 一条权值为 Di的无向边. 图中可能有重边或自环. Output 仅包含一个整数,表示最大

BZOJ 3105: [cqoi2013]新Nim游戏 [高斯消元XOR 线性基]

以后我也要用传送门! 题意:一些数,选择一个权值最大的异或和不为0的集合 终于有点明白线性基是什么了...等会再整理 求一个权值最大的线性无关子集 线性无关子集满足拟阵的性质,贪心选择权值最大的,用高斯消元判断是否和已选择的线性相关 每一位记录pivot[i]为i用到的行 枚举要加入的数字的每一个二进制为1的位,如果有pivot[i]那么就异或一下(消元),否则pivot[i]=这个数并退出 如果最后异或成0了就说明线性相关... #include <iostream> #include &l

HDU 3949 XOR(线性基)

题意:给出一组数,求最小的第k个由这些数异或出来的数. 先求这组数的线性基.那么最小的第k个数显然是k的二进制数对应的线性基异或出来的数. # include <cstdio> # include <cstring> # include <cstdlib> # include <iostream> # include <vector> # include <queue> # include <stack> # includ

BZOJ 2115 [Wc2011] Xor ——线性基

[题目分析] 显然,一个路径走过两边是不需要计算的,所以我么找到一条1-n的路径,然后向该异或值不断异或简单环即可. 但是找出所有简单环是相当复杂的,我们只需要dfs一遍,找出所有的环路即可,因为所有的简单环都可以经过各种各样的异或得到. 然后线性基,在从高位向低位贪心即可,至于证明,需要拟阵的相关知识. [代码] #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath>

【BZOJ2115】【Wc2011】 Xor 线性基 异或最长路

#include <stdio.h> int main() { puts("转载请注明出处谢谢"); puts("http://blog.csdn.net/vmurder/article/details/43410545"); } 题意:找一条异或最长路. 题解:先随便来一条路径,然后我们发现这条路径上可以随便加简单环(不管有没有共点共边). 就是因为可以先从某点走到环上来一圈再走回来,这样来去的路径被搞没了,简直污得不行. 然后我们可以用线性基来决定去

bzoj 2115 Xor - 线性基 - 贪心

题目传送门 这是个通往vjudge的虫洞 这是个通往bzoj的虫洞 题目大意 问点$1$到点$n$的最大异或路径. 因为重复走一条边后,它的贡献会被消去.所以这条路径中有贡献的边可以看成是一条$1$到$n$的简单路径加上若干个环. 因此可以找任意一条路径,然后找出所有环扔进线性基跑出最大异或和. 但是找出所有环可能会T掉,但是仔细画图发现,并不需要找出所有环,例如: 在上图中,你并不需找出所有的环,只用找出1 - 3 - 4 - 2和3 - 5 - 6 - 4这两个环,它们异或后就能得到环1 -