【牛客】子串(思维、扫描线)

90nwyn

2020-09-25 15:14:46

Personal

[题目链接](https://ac.nowcoder.com/acm/contest/7329/E) ------------ 枚举区间的右端点,求合法的左端点数 ------------ ```cpp #include <bits/stdc++.h> using namespace std; #define lowbit(x) (x&-x) typedef long long ll; const int M=2e6+5; int n,p[M],pos[M],l[M],r[M],tot,c[M]; ll ans; struct d { int t,x,v; bool operator<(const d &a)const{return t<a.t;} }opt[M]; void upd(int x,int v){for(int i=x;i<=n;i+=lowbit(i))c[i]+=v;} int que(int x){int res=0;for(int i=x;i;i-=lowbit(i))res+=c[i];return res;} int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&p[i]); pos[p[i]]=i; } for(int i=1;i<=n;i++) { l[i]=i; if(p[i]<=i)while(l[i]>1&&p[l[i]-1]<=i)l[i]=l[l[i]-1]; } for(int i=n;i>=1;i--) { r[i]=i; if(p[i]>=i)while(r[i]<n&&p[r[i]+1]>=i)r[i]=r[r[i]+1]; } for(int i=1;i<=n;i++)if(i<=pos[i]&&pos[i]<=r[i])opt[++tot]={pos[i],i,1},opt[++tot]={r[i]+1,i,-1}; sort(opt+1,opt+1+tot); for(int now=1,i=1;i<=n;i++) { while(now<=tot&&opt[now].t<=i)upd(opt[now].x,opt[now].v),now++; if(l[i]<=pos[i]&&pos[i]<=i)ans+=que(pos[i])-que(l[i]-1); } printf("%lld\n",ans); return 0; } ``` ------------ 满足题意的区间必然有 $l$ $oxr$ $(l+1)$ $...$ $r$ $=p[l]$ $oxr$ $p[l+1]$ $...$ $p[r]$ 即$l$ $oxr$ $(l+1)$ $...$ $r$ $oxr$ $p[l]$ $oxr$ $p[l+1]$ $...$ $p[r]=0$ 问题等价于求异或和为$0$的子区间数量 ------------ ```cpp #include <bits/stdc++.h> using namespace std; typedef long long ll; const int M=1e6+5; mt19937_64 rng(time(0)); int n,p[M]; ll haxi[M]; unordered_map<ll,int> mp; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&p[i]); ll tmp=rng(); haxi[p[i]]^=tmp; haxi[i]^=tmp; } for(int i=1;i<=n;i++)haxi[i]^=haxi[i-1]; ll ans=0; for(int i=0;i<=n;i++) { ans+=mp[haxi[i]]; mp[haxi[i]]++; } printf("%lld\n",ans); return 0; } ```