问题 C: 与非
时间限制: 2 Sec 内存限制: 256 MB提交: 54 解决: 34
[提交][状态][讨论版]
题目描述
作为一名新世纪共产主义的接班人,你认识到了资本主义的软弱性与妥协性,决定全面根除资本主义,跑步迈入共产主义。但是当你即将跨入共产主义大门的时候,遇到了万恶的资本家留下的与非电路封印,经过千辛万苦的研究,你终于把复杂的破解转变成了以下问题:
初始时你有一个空序列,之后有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
最后,爆零 = = ,性质找错了 好尴尬 是我太弱了
题解:*@***#**@* 什么真值表,线段树,都去死吧 。 。 。
神一般的做法:
要求的是[L,R] 区间内的值,考虑到异或具有可减性,我们可以用sum[r]-sum[l-1] 来求得
可减性 : 1^1^0^0^1^1^0^1^0 ==1
1^1^0^0 ==0
求 1^1^0^1^0 =(1^1^0^0^1^1^0^1^0)^(1^1^0^0) ==1
原因:连续的1,0异或结果只与1个数的奇偶性有关,奇则为1,偶则为0.(不信试一试)
Then 易得nand[i,j]=!(nand[i,j-1]&val[j])
设f[i] 表示nand[1,i] , sum[i]=f[1]^f[2]^……^f[n]。
考虑 两个式子 !(val[l]&val[l+1]) !(f[l]&val[l+1])
若 val[l]==f[l] 则再往后 结果都一样 所以 ans=sum[r]^sum[l-1]
若 val[l]! =f[l] 则一个为1,另一个为0 再往后 若 val[i] ==1 则两个值 又1—>0,0—>1;
一直保持不同,但一旦遇到0,二者均变为1 再往后则一直保持一致,我们需要考虑
在连续的 1—>0,0—>1过程中两个式子出现一的次数是否一致,
若一致 ans=sum[r]^sum[l-1], 若不一致 ans=sum[r]^sum[l-1]^1
接下来考虑如何统计1的个数,设从l往后第一个0的下标为pos,则之前两式交替出现0,1的次数即为pos-l
若(pos-l)%2==0 则两式出现一的次数相等 ans=ans=sum[r]^sum[l-1];
若(pos-l)%2==1 无论谁多一个1,谁少一个1,秩序再^1即可, ans=ans=sum[r]^sum[l-1]^1;
第一个0的下标可以用链表在读入时求得,O(1)即可得到其下标。链表具体实现过程留给读者思考(代码)
总之,这道题很考思维,代码量却很小,很不错。
最后%一发大佬lc
代码如下:
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
const int M=4000000+10;
int n,ans,cnt,p;
int pre[M],nxt[M];
bool sum[M],f[M],val[M];
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
int main(){
n=read();
for(int i=1;i<=n;i++){
int opt,l,r;
opt=read();
if(opt==1){
l=read()^ans;
val[++cnt]=l;
if(!val[cnt]){
nxt[p]=cnt;
p=cnt;
}else pre[cnt]=p;
if(cnt==1)
f[1]=sum[1]=val[cnt];
else{
f[cnt]=!(f[cnt-1]&val[cnt]);
sum[cnt]=sum[cnt-1]^f[cnt];
}
}else{
l=read();r=read();
if(ans==1){
l=cnt-l+1;r=cnt-r+1;
swap(l,r);
}
if(l==r) {printf("%d\n",ans=(int)val[l]);continue;}
if(val[l]==f[l]) {printf("%d\n",ans=sum[r]^sum[l-1]);continue;}
else{
int pos=nxt[pre[l]];
if(val[l]==0) pos=nxt[l];
pos=min(pos-1,r);
int pd=pos-l+1;
if(pd&1) {printf("%d\n",ans=sum[r]^sum[l-1]^1);continue;}
else {printf("%d\n",ans=sum[r]^sum[l-1]);continue;}
}
}
}
return 0;
}