BZOJ 2728 HNOI2012 与非 高斯消元

题目大意:给定k位二进制下的n个数,求[l,r]区间内有多少个数能通过这几个数与非得到

首先观察真值表 我们有A nand A = not A

然后就有not ( A nand B ) = A and B

与和非都弄到了,我们就可以做出一切逻辑运算了,比如说或和异或

A or B = not ( ( not A ) and ( not B ) )

A xor B = ( A or B ) and ( A nand B )

然后我们对于位运算可以发现一个性质

对于某两位来说,如果对于每一个数,这两位上的值都是相同的,那么这两位无论怎么计算最终结果都会是相同的

比如说10(1010)和7(0111),第一位和第三位都是相同的,所以最后无论怎么计算,这两位都是一样的

然后我们这么处理:

对于每一位,我们枚举每一个数,若该数该位上为0,我们就对这个数取非

然后把所有数取与

该位上都是1,所以取与后一定是1;对于其他位,只要有这两位不同的数存在,那么这位一定是0

最后取与的结果中与该位全部相同的位都是1,其余都是0

对于每一位这样处理,标记去重,然后可以得到线性基,保证每一位存在且仅存在于线性基中的一个数上

拿去从大到小贪心处理即可 得到二进制序列即为答案

此题有坑 题目描述中1<=L<=R<=10^18 但是第七个点L=0 坑死一票人啊

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define M 1010
using namespace std;
typedef long long ll;
int n,k;
ll digit,l,r,a[M],basis[70],tot;
bool v[70];
ll Get_Digit(ll x)
{
	if(x==-1)
		return -1;//坑比!!!
	ll now=0,re=0;
	int i;
	for(i=1;i<=tot;i++)
		if( (now|basis[i])<=x )
			now|=basis[i],re|=(1ll<<tot-i);
	return re;
}
int main()
{

	//freopen("nand.in","r",stdin);
	//reopen("nand.out","w",stdout);

	int i,j;
	ll now;
	cin>>n>>k>>l>>r;
	digit=(1ll<<k)-1;
	for(i=1;i<=n;i++)
		scanf("%lld",&a[i]);
	for(i=k-1;~i;i--)
		if(!v[i])
		{
			now=digit;
			for(j=1;j<=n;j++)
				if( a[j]&(1ll<<i) )
					now&=a[j];
				else
					now&=~a[j]&digit;
			basis[++tot]=now;
			for(j=0;j<=i;j++)
				if( now&(1ll<<j) )
					v[j]=1;
		}
	cout<<Get_Digit(r)-Get_Digit(l-1)<<endl;
}
//lld
时间: 2025-01-21 22:25:03

BZOJ 2728 HNOI2012 与非 高斯消元的相关文章

BZOJ 3143 HNOI2013 游走 高斯消元 期望

这道题是我第一次使用高斯消元解决期望类的问题,首发A了,感觉爽爽的.... 中文题目,就不翻大意了,直接给原题: 一个无向连通图,顶点从1编号到N,边从1编号到M. 小Z在该图上进行随机游走,初始时小Z在1号顶点,每一步小Z以相等的概率随机选 择当前顶点的某条边,沿着这条边走到下一个顶点,获得等于这条边的编号的分数.当小Z 到达N号顶点时游走结束,总分为所有获得的分数之和. 现在,请你对这M条边进行编号,使得小Z获得的总分的期望值最小. 输出最小的总分期望值. Solution: 这题贪心很明显

bzoj 2115: [Wc2011] Xor xor高斯消元

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

BZOJ 2115 Wc2011 Xor DFS+高斯消元

题目大意:给定一个无向图,每条边上有边权,求一条1到n的路径,使路径上权值异或和最大 首先一条路径的异或和可以化为一条1到n的简单路径和一些简单环的异或和 我们首先DFS求出任意一条1到n的简单路径以及图中所有最简单的简单环(环上不存在两个点可以通过环外边直连) 然后在一些数中选出一个子集,使它们与一个给定的数的异或和最大,这就是高斯消元的问题了 利用高斯消元使每一位只存在于最多一个数上 然后贪心求解即可 #include<cstdio> #include<cstring> #in

BZOJ 3270 博物馆 期望DP+高斯消元

题目大意:给定一张无向连通图,两个人初始各在某个点上,每个时刻每个人会不动或任选出边走,求两人最终期望在哪里相遇 把点数平方,原图上的两个点(x,y)变成新图上的一个点 然后令A为这个图的邻接矩阵(若两人在同一点上则没有出边,否则按概率转移),S为初始行向量(S[(a,b)]=1),ans为答案行向量 那么有ans=S+SA+SA^2+SA^3+... =S(I-A^+∞)/(I-A) =S/(I-A) 于是有ans*(I-A)=S 于是对I-A的转置求高斯消元即可. 和驱逐猪猡那题的思路很像.

bzoj 2784 [JLOI2012]时间流逝——树上高斯消元

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2784 一个状态可以加很多个能量圈,但减少能量圈的情况只有一种.所以可以用树来刻画. 然后就变成树上高斯消元的套路了.注意根节点的 P 等于 0 . 发现不是要求 dp[ 1 ] 就必须在那个式子里设出 a*dp[ 1 ] 之类的. 据说树上的点大概有 1.2*106 个.大概就是贝尔数吧. #include<cstdio> #include<cstring> #include

BZOJ 2322 BeiJing2011 梦想封印 高斯消元

题目大意:给定一张带权无向图,每次删去一条边并询问从点1出发走一条路径可以走出多少种不同的边权异或和 删边不好做 首先倒着做 把删边改成加边 回忆2115那题的做法 我们可以把一条路径的异或和拆成一条简单路径和一些环的异或值 2115是求最大异或和  这个题是求异或和的个数 因此我们维护两个集合 环的异或和集合和路径的异或和集合 这里说的路径包括原地不动 即从1到1的路径 如果一个环的异或和能被其它环线性表示 那么这个环对答案显然没有贡献 于是这个环就可以从集合中删掉 因此环的集合要维护一个线性

BZOJ 3143: [Hnoi2013]游走( 高斯消元 )

我一开始的想法是设f(x)表示点x到N路径的期望长度, 那么f(u) = (∑f(v)+w(u,v)) / degreeu, f(N)=0, 我们代入入消元应该可以得到f(1)关于各条边长的关系式f(1)=∑we..然后贪心, 按照他们的系数来给边权...但是不会实现..但是我感觉是可行的..PoPoQQQ题解:http://blog.csdn.net/PoPoQQQ/article/details/42234607 ---------------------------------------

BZOJ 4004: [JLOI2015]装备购买 [高斯消元同余 线性基]

和前两(一)题一样,不过不是异或方程组了..... 然后bzoj的新数据是用来卡精度的吧..... 所有只好在模意义下做啦 只是巨慢无比 #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <bitset> using namespace std; typedef long lon

BZOJ 3143 游走(高斯消元)

题意:一个无向连通图,顶点从1编号到n,边从1编号到m.小Z在该图上进行随机游走,初始时小Z在1号顶点,每一步小Z以相等的概率随机选择当前顶点的某条边,沿着这条边走到下一个顶点,获得等于这条边的编号的分数.当小Z 到达n号顶点时游走结束,总分为所有获得的分数之和. 现在,请你对这m条边进行编号,使得小Z获得的总分的期望值最小. 思路:显然,需要求出每条边的期望经过次数,然后排序贪心赋值即可,但是每条边的期望经过次数是什么呢? 是 E(e)=E(u)/D(u) + E(v)/D(v) (u,v∈e