loj#6187. Odd
upt:由于是异或,正确性不一定能保证。可以考虑对每个权值随机赋值加强正确性。
首先有个性质,假如这个区间合法,那么这个区间的异或和等于这个区间出现过的数的异或和。
出现过的数自然想到 HH 的项链,考虑记 ,然后一个数只对 有贡献。
记 即前缀异或和。
为区间出现过的数的异或和。
那么,答案就是 ,转换下 ,即找多少个 起来与 相等的。
如何维护 呢,对于一个数 ,它对左端点影响区间是 (因为我们查找就是找 ,注意是端点不是区间,区间的话需要再抵消上一次的贡献),我们要让这整个端点区间异或上 (因为查找就是找 是当前枚举的,)。对于 我们可以考虑就是它本来的权值。
考虑 可能很大,需要用 查找,发现可以用分块,对于每个块开一个 表,整个序列初始权值为 ,然后其他操作显然。
我的代码应该是最劣解 /cy
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | #include <cstdio> #include <algorithm> #include <iostream> #include <cstring> #include <vector> #include <cmath> #include <queue> #include <map> #include <ctime> #define ll long long using namespace std; int rd() { int f=1,sum=0; char ch= getchar (); while (! isdigit (ch)) { if (ch== '-' ) f=-1;ch= getchar ();} while ( isdigit (ch)) {sum=(sum<<3)+(sum<<1)+ch- '0' ;ch= getchar ();} return sum*f; } ll lrd() { ll f=1,sum=0; char ch= getchar (); while (! isdigit (ch)) { if (ch== '-' ) f=-1;ch= getchar ();} while ( isdigit (ch)) {sum=(sum<<3)+(sum<<1)+ch- '0' ;ch= getchar ();} return sum*f; } const int N=( int )(2e5+5),M=( int )(1e6+5),B=500,mod=4991; ll s[N],val[M],id[N],L[B],R[B],tag[B],Bsum[N]; int a[N],las[M],n,bl=450; struct HASH { struct node { int cnt,nex; ll val; }H[mod+2]; int head[mod+2],tot; void clear() { tot=0; memset (head,0, sizeof (head)); } int Find(ll x) { for ( int i=head[x&mod];i;i=H[i].nex) if (H[i].val==x) return i; return -1; } int query(ll x) { int h=Find(x); if (~h) return H[h].cnt; return 0; } void ins(ll x) { int h=Find(x); if (~h) ++H[h].cnt; else { H[++tot].cnt=1; H[tot].nex=head[x&mod]; H[tot].val=x; head[x&mod]=tot; } } }Hash[B]; ll get_rand() { return (1ll* rand ()<<31| rand ()); } void build( int x) { Hash[x].clear(); for ( int i=L[x];i<=R[x];i++) Bsum[i]^=tag[x],Hash[x].ins(Bsum[i]); tag[x]=0; } void update( int l, int r,ll v) { if (id[l]==id[r]) { for ( int i=l;i<=r;i++) Bsum[i]^=v; build(id[l]); } else { for ( int i=l;i<=R[id[l]];i++) Bsum[i]^=v; for ( int i=L[id[r]];i<=r;i++) Bsum[i]^=v; build(id[l]); build(id[r]); for ( int i=id[l]+1;i<id[r];i++) tag[i]^=v; } } int query( int l, int r,ll v) { ll res=0; if (id[l]==id[r]) { build(id[l]); for ( int i=l;i<=r;i++) res+=(Bsum[i]==v); } else { build(id[l]); build(id[r]); for ( int i=l;i<=R[id[l]];i++) res+=(Bsum[i]==v); for ( int i=L[id[r]];i<=r;i++) res+=(Bsum[i]==v); for ( int i=id[l]+1;i<id[r];i++) res+=Hash[i].query((v^tag[i])); } return res; } int main() { // freopen("odd5.in","r",stdin); srand ( time (0)); int mx=0; n=rd(); for ( int i=1;i<=n;i++) a[i]=rd(),id[i]=(i-1)/bl+1,mx=max(mx,a[i]); for ( int i=0;i<=mx;i++) val[i]=get_rand(); for ( int i=1;i<=id[n];i++) L[i]=(i-1)*bl+1,R[i]=i*bl; R[id[n]]=n; for ( int i=1;i<=id[n];i++) build(i); for ( int i=1;i<=n;i++) Bsum[i]=s[i-1],s[i]=(s[i-1]^val[a[i]]); ll ans=0; for ( int i=1;i<=n;i++) { update(las[a[i]]+1,i,val[a[i]]); las[a[i]]=i; ans+=query(1,i,s[i]); } printf ( "%lld" ,ans); } |
__EOF__

本文作者:F x o r G
本文链接:https://www.cnblogs.com/xugangfan/p/15153175.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
本文链接:https://www.cnblogs.com/xugangfan/p/15153175.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】