题解:B4106 [CSP-X2024 山东] 翻硬币
TainityAnle · · 题解
全场最劣解祭。
题意
给定一个初始为
思路
容易发现一个点被翻奇数次就会变成
每次翻转一个区间,可以用区间加,但是线段树的代码过于复杂,会吓到小学组的孩子们,我选择使用优化后的暴力。
我们可以给这个区间分成若干个长度为
对于中间的整块,给每一个块打上一个加
查询的时候,只需要将每个点所在块的加
AC Code
#include<bits/stdc++.h>
using namespace std;
int n,m,x,y,pos[200050],len,a[200005],b[500],L[500],R[500];//a是每个数暴力加的次数,b是每个块的标记
void add(int l,int r){
int p=pos[l],q=pos[r];
if(p==q){//特判修改端点在一个块的情况
for(int i=l;i<=r;i++) a[i]++;
return;
}
for(int i=l;i<=R[p];i++) a[i]++;//处理左边散块
for(int i=L[q];i<=r;i++) a[i]++; //处理右边散块
for(int i=p+1;i<=q-1;i++) b[i]++; //处理整块
}
int main(){
cin>>n>>m;
len=sqrt(n);
for(int i=1;i<=len;i++){
L[i]=(i-1)*sqrt(n)+1;
R[i]=i*sqrt(n);
}
if(R[len]<n){
len++;
L[len]=R[len-1]+1,R[len]=n;
}
for(int i=1;i<=len;i++)
for(int j=L[i];j<=R[i];j++)
pos[j]=i;
//以上是分块预处理,维护每个块左、右端点,每个点属于哪个块
for(int i=1;i<=m;i++){
cin>>x>>y;
add(x,y);
}
for(int i=1;i<=n;i++) {
int val=a[i]+b[pos[i]];
cout<<(val&1);
}
return 0;
}
这份代码以