欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

2021牛客暑期多校训练营3 I Kuriyama Mirai and Exclusive Or 差分 + 二进制分治

发布时间:2023/12/4 编程问答 54 豆豆
生活随笔 收集整理的这篇文章主要介绍了 2021牛客暑期多校训练营3 I Kuriyama Mirai and Exclusive Or 差分 + 二进制分治 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

传送门

文章目录

  • 题意:
  • 思路:

题意:

给你一个数组aaa,让你实现以下两个操作之后输出数组aaa

n≤6e5,ai≤230−1n\le6e5,a_i\le2^{30}-1n6e5,ai2301

思路:

下面介绍的思路清奇,反正我想不到。
对于两个操作,显然对于异或操作顺序是没有影响的,所以对于第一个操作可以直接打个差分即可。
对于第二个操作,我们本能的想把括号拆开,但是括号中是加法对于异或来说没有分配律,所以考虑(x+(i−l))(x+(i-l))(x+(il))将加法转换成或,假设xxx111的最低位置在2k2^k2k处,如果i−l<2ki-l<2^kil<2k,那么此时(x+(i−l))=(x∣(i−l))(x+(i-l))=(x|(i-l))(x+(il))=(x(il)),此时ai⊕(x+(i−l))=ai⊕(x∣(i−l))=ai⊕x⊕(i−l)a_i\oplus (x+(i-l))=a_i\oplus (x|(i-l))=a_i\oplus x \oplus (i-l)ai(x+(il))=ai(x(il))=aix(il),也就是先让iii位置异或上xxx,让后让[i,i+2k−1][i,i+2^k-1][i,i+2k1]的位置分别异或上0,1,...,2k−10,1,...,2^k-10,1,...,2k1。所以我们记一个f[k][i]f[k][i]f[k][i]数组表示是否需要将[i,i+2k−1][i,i+2^k-1][i,i+2k1]的位置分别异或上0,1,...,2k−10,1,...,2^k-10,1,...,2k1,之后将x+(1<<k),l+(1<<k)x+(1<<k),l+(1<<k)x+(1<<k),l+(1<<k)即可。
这样一直推下去,到最后会剩下一段小区间,这段区间我们直接倒着来一遍即可,因为他的后k−1k-1k1位都是000,所以也满足上面的性质。
我们记了一个fff数组,个人感觉怎么用它也是一个比较难想到的点。我们可以用类似倍增实则是倍增的逆过程来递推下去,是一种分治的思想。
考虑当前遍历到了f[i][k]f[i][k]f[i][k],那么我们可以将其分成两段来看,两段分别是[i,i+2k−1−1],[i+2k−1,i+2k−1][i,i+2^{k-1}-1],[i+2^{k-1},i+2^{k}-1][i,i+2k11],[i+2k1,i+2k1]
对于第一段,我们直接将f[i][k−1]f[i][k-1]f[i][k1]标记一下,让后等分治下去处理即可。对于
对于第二段,我们将f[i+2k−1][k−1]f[i+2^{k-1}][k-1]f[i+2k1][k1]标记一下,这样还不够,因为这一位及其之后应该异或上2k−1,2k−1+1,...,2k−12^{k-1},2^{k-1}+1,...,2^k-12k1,2k1+1,...,2k1,根据上面的转换公式,我们可以将i+2k−1i+2^{k-1}i+2k1差分数组的位置异或上2k−12^{k-1}2k1即可,这样就可以不断的分治递推下去,代码写起来很像倍增的逆过程。。

// Problem: Kuriyama Mirai and Exclusive Or // Contest: NowCoder // URL: https://ac.nowcoder.com/acm/contest/11254/I // Memory Limit: 131072 MB // Time Limit: 6000 ms // // Powered by CP Editor (https://cpeditor.org)//#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math") //#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native") //#pragma GCC optimize(2) #include<cstdio> #include<iostream> #include<string> #include<cstring> #include<map> #include<cmath> #include<cctype> #include<vector> #include<set> #include<queue> #include<algorithm> #include<sstream> #include<ctime> #include<cstdlib> #include<random> #include<cassert> #define X first #define Y second #define L (u<<1) #define R (u<<1|1) #define pb push_back #define mk make_pair #define Mid ((tr[u].l+tr[u].r)>>1) #define Len(u) (tr[u].r-tr[u].l+1) #define random(a,b) ((a)+rand()%((b)-(a)+1)) #define db puts("---") using namespace std;//void rd_cre() { freopen("d://dp//data.txt","w",stdout); srand(time(NULL)); } //void rd_ac() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//AC.txt","w",stdout); } //void rd_wa() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//WA.txt","w",stdout); }typedef long long LL; typedef unsigned long long ULL; typedef pair<int,int> PII;const int N=1000010,mod=1e9+7,INF=0x3f3f3f3f; const double eps=1e-6;int n,m; int a[N]; int d[N],f[30][N];int main() { // ios::sync_with_stdio(false); // cin.tie(0);scanf("%d%d",&n,&m);for(int i=1;i<=n;i++) scanf("%d",&a[i]);while(m--) {int op,l,r,x; scanf("%d%d%d%d",&op,&l,&r,&x);if(op==0) d[l]^=x,d[r+1]^=x;else {int k=0;while(l+(1<<k)-1<=r) {if(x>>k&1){int now=l+(1<<k);d[l]^=x; d[now]^=x;f[k][l]^=1;x+=(1<<k); l=now; }k++;}while(l<=r) {if(l+(1<<k)-1<=r) {int now=l+(1<<k);d[l]^=x; d[now]^=x;f[k][l]^=1;x+=(1<<k); l=now; }k--;}}}for(int i=29;i>=1;i--) {for(int j=1;j<=n;j++) {if(f[i][j]) {f[i-1][j]^=1;f[i-1][j+(1<<(i-1))]^=1;d[j+(1<<(i-1))]^=(1<<(i-1));d[j+(1<<i)]^=(1<<(i-1));}}}for(int i=1;i<=n;i++) d[i]^=d[i-1];for(int i=1;i<=n;i++) printf("%d ",a[i]^d[i]);return 0; } /**/

总结

以上是生活随笔为你收集整理的2021牛客暑期多校训练营3 I Kuriyama Mirai and Exclusive Or 差分 + 二进制分治的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。