题意:
有一个由0和1组成的数组,定义一种新运算azui,1 azui 1 = 1,1 azui 0 = 0,0 azui 1 = 0,0 azui 0 = 1,给出一个长度为n的该数组,以及m个查询l,r,表示将区间[l,r]从l一个一个azui到r的值。
题解:
额,先说说稍微复杂一点的做法,可以发现,这个azui运算是满足结合律的,于是你就可以用线段树来做了
但其实,有更简单的方法,数数0的个数就可以了,奇数为0,偶数为1,代码附上我考试时的心路历程,里面有证明
code:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
const int MAXN=1000005;
using namespace std;
int n,m,l,r,sum[MAXN];
bool a[MAXN];
inline void Read(int &Ret){
char ch;bool flag=0;
for(;ch=getchar(),ch<'0'||ch>'9';)if(ch=='-')flag=1;
for(Ret=ch-'0';ch=getchar(),'0'<=ch&&ch<='9';Ret=Ret*10+ch-'0');
flag&&(Ret=-Ret);
}
inline void Read(bool &Ret){
char ch;bool flag=0;
for(;ch=getchar(),ch<'0'||ch>'9';)if(ch=='-')flag=1;
for(Ret=ch-'0';ch=getchar(),'0'<=ch&&ch<='9';Ret=Ret*10+ch-'0');
flag&&(Ret=-Ret);
}
int main()
{
//freopen("azui.in","r",stdin);
//freopen("azui.out","w",stdout);
Read(n);
for(int i=1;i<=n;i++)
{
Read(a[i]);
sum[i]=sum[i-1];
if(!a[i]) sum[i]++;
}
Read(m);
for(int i=1;i<=m;i++)
{
Read(l); Read(r);
int cnt=sum[r]-sum[l-1];
if(cnt&1) putchar('0');
else putchar('1');
putchar(10);
}
}
/*
5
1 0 1 0 1
5
2 3
3 4
4 5
1 3
1 4
print 0 0 0 0 1
灯泡状态相同为1,相异为0
0 azui 0 = 1
0 azui 0 azui 1 = 0 azui 1 azui 0 = 1 azui 0 azui 0 = 1;满足交换律
0 azui 0 azui 0 = 0; 1 azui 1 azui 1 = 1;满足交换律
1 azui 1 azui 0 = 1 azui 0 azui 1 = 0 azui 1 azui 1 = 0;满足交换律
要是真的满足交换律,就简单了
验证一下,暴力嘛,嘿嘿。
1 0 1 1 0 1 0 0 0 1
5个1,5个0,最后结果应该是1
0 0 0 1 1 0 1 0 0
其实最后结果为0
看来是不满足交换律了
要是当前ans为1,那么遇到0,ans便会为0
要是当前ans为0,那么遇到0,ans便会为1!!!这两句话就是证明,可以发现1并不会影响结果
那么要是我开一个数组,a[i]储存左边和右
边第一个状态为0的数呢?
我记得用map是可以nlogn求的吧
map<int,int> M;
for(int i=1;i<=n;i++)
{
int t=-1;
if(M.count(0))
t=M[!a[i]];
M[a[i]]=i;
left[a[i]]=t;
}
那么这就是说,1是不会影响结果的,
影响结果的只会是0?
哈哈哈哈,找到规律了
1 0 0 ans=1
0 0 0
1 1 0 0
1 0 0 0
那么开始ans的值会不会有影响?
若是开始ans为1,那么有奇数个0,ans=0
若是开始ans为0,那么有奇数个0,ans=1
但是事实上,ans开始为0,则意味着有偶数个0
所以说只需要判断0的个数即可
*/