【NOIP校內模擬】T2 字胡串(分治)
阿新 • • 發佈:2018-12-30
%%%%%%%%%%%lst神仙 這是他的做法 吊了標算
對於這種有多少區間滿足要求的 我們套路的用分治做 每次都統計左端點在左半邊 右端點在右半邊的個數
設f(i) 表示當前點到中間分割點的最大值,g(i)表示當前點到中間分割點的或和
我們發現 g(i)≥f(i) 所以只需找到g[i]=f[i]的區間就好
然後f肯定是單調遞增的
所以可以維護雙指標
邊界條件很壞壞 膜lst神仙啊
#include<bits/stdc++.h> #define N 1000005 #define int long long using namespace std; template<class T> inline void read(T &x) { x=0; int f=1; static char ch=getchar(); while((!isdigit(ch))&&ch!='-') ch=getchar(); if(ch=='-') f=-1; while(isdigit(ch)) x=x*10+ch-'0',ch=getchar(); x*=f; } int n,s[N],f[N],g[N],ans; inline void solve(int l,int r) { if(l>=r) return; int mid=(l+r)>>1; f[mid]=s[mid],f[mid+1]=s[mid+1]; for(int i=mid-1;i>=l;i--) f[i]=max(s[i],f[i+1]); for(int i=mid+2;i<=r;i++) f[i]=max(s[i],f[i-1]); g[mid]=s[mid],g[mid+1]=s[mid+1]; for(int i=mid-1;i>=l;i--) g[i]=s[i]|g[i+1]; for(int i=mid+2;i<=r;i++) g[i]=s[i]|g[i-1]; int pos=mid; for(int i=mid;i>=l;i--) //左端點 { if(f[i]==g[i]) { while(pos<r&&((g[pos+1]|g[i])==g[i])&&f[pos+1]<=f[i]) pos++; //1.沒越界 2.是子集 3.最大值在左邊 ans-=pos-mid; } } pos=mid+1; for(int i=mid+1;i<=r;i++) { if(f[i]==g[i]) { while(pos>l&&((g[pos-1]|g[i])==g[i])&&f[pos-1]<f[i]) pos--; ans-=mid-pos+1; } } solve(l,mid); solve(mid+1,r); } main() { read(n); for(int i=1;i<=n;i++) read(s[i]); ans=n*(n-1)/2; solve(1,n); cout<<ans; return 0; }