暑假集训 T3 与非

问题 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

6       N<=4000000    M1<=3900000 M2<=100000
7       N<=4000000    M1<=3900000 M2<=100000
8       N<=4000000    M1<=3900000 M2<=100000
9       N<=4000000    M1<=3900000 M2<=100000
10     N<=4000000    M1<=3900000 M2<=100000
 
对于所有数据,满足N<=4000000,M1<=3900000,M2<=100000,x={0,1},L<=R。

第一眼,wc 题我都没看懂  ,这么弱赶紧滚粗吧 = = 
第二眼,哈哈,看懂了(其实 老师做了解释)   = =
第三眼,数据结构,不过貌似不可做啊                = =
第四眼,还是看有没有什么 一颗赛艇  的性质吧 = =

最后,爆零    = =  ,性质找错了   好尴尬   是我太弱了

题解:*@***#**@*   什么真值表,线段树,都去死吧  。 。 。

神一般的做法:

要求的是[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;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值