膜拜神犇lc 与非

     

问题 C: 与非

时间限制: 2 Sec  内存限制: 256 MB

题目描述

作为一名新世纪共产主义的接班人,你认识到了资本主义的软弱性与妥协性,决定全面根除资本主义,跑步迈入共产主义。但是当你即将跨入共产主义大门的时候,遇到了万恶的资本家留下的与非电路封印,经过千辛万苦的研究,你终于把复杂的破解转变成了以下问题:

初始时你有一个空序列,之后有N个操作。

操作分为一下两种:

1 x:在序列末尾插入一个元素x(x=0或1)。

2 L R:定义nand[L,R]为序列第L个元素到第R个元素的与非和,询问nand[L,L]^nand[L,L+1]^nand[L,L+2]^......^nand[L,R]。

Nand就是先与,再取反

输入

从文件nand.in中读入数据。

输入第一行一个正整数N,表示操作个数。

接下来N行表示N个操作。

为了体现程序的在线性,记lastans为上一次操作二的回答,初始lastans=0,。对于操作1,你需要对x异或lastans。对于操作二,设现在序列中的元素个数为M,如果lastans=1,那么你需要作如下操作:L=M-L+1,R=M-R+1,swap(L,R)

输出

输出到nand.out中。

输出有多行。为对于每一个操作二的回答。

样例输入

61 11 11 02 1 22 1 32 2 3

样例输出

100

提示

【数据规模和约定】

数据点 N的规模 操作一的个数M1 操作二的个数M2

1 N<=1000 M1<=500 M2<=500

2 N<=1000 M1<=500 M2<=500

3 N<=200000 M1<=100000 M2<=100000

4 N<=200000 M1<=100000 M2<=100000

5 N<=1000000 M1<=900000 M2<=100000

       考试时数据范围写错了,吓死人。。。正解是什么真值表加线段树,没看明白,但神犇lc考场上AC了,方法很神奇,而且,超第二的500多ms,啧。。挺难懂,但学明白了。

      不扯了:设nand[i,j]是从i到j的与非和,f[i]表示nand[1,i].sum[i]=f[1]^f[2]^.....f[i]

       那么sum就是f的前缀异或和。

      那现在来证一个东西,数列中一旦出现零,nand的值一定变成同一个值(0&任何数等于0),那么找的数列有零后,nand[i,j]==f[j],这个时候前缀异或和就派上用场了。因为异或的逆运算也是异或sum[r]^sum[k-1]剩下的答案就出来了。

      找的思路是:先暴力找,找到记录的cnt==f[i]时,跳出。。

     最后,%lc   orz   orz   orz

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
int read()
{
	int sum=0,f=1;char x=getchar();
	while(x<'0'||x>'9'){if(x=='-')f=-1;x=getchar();}
	while(x>='0'&&x<='9'){sum=sum*10+x-'0';x=getchar();}
	return sum*f;
}
int n,tot=0,f[3900005],ans=0,sum[3900005],p=0,a[3900005];
int get(int l,int r)
{
	int su=a[l],cnt=a[l],i;
	for(i=l+1;i<=r;i++)
	{
	   cnt=!(cnt&a[i]);
	   if(cnt==f[i])break;
	   su^=cnt;
	}
	if(i!=r+1)su^=sum[r]^sum[i-1];
	return su;
}
int main()
{
	n=read();int x,l,r;
	while(n--)
	{
		x=read();
		if(x==1)
		{
			l=read();l^=ans;
			a[++tot]=l;
			if(tot!=1)f[tot]=!(l&f[tot-1]),sum[tot]=sum[tot-1]^f[tot];
			else f[tot]=l,sum[tot]=f[tot];
		}
		else
		{
			l=read();r=read();
			if(ans==1){l=tot-l+1,r=tot-r+1,swap(l,r);}
			if(l==r)ans=a[l];
			else ans=get(l,r);
			printf("%d\n",ans);
		}
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值