题目
给出一个长度为(n)的数列(a),求
[sum_{i=1}^nsum_{j=i}^n[gcd(a_{isim j});xor;or(a_{isim j})=k]
]
分析
考虑如何优化这个(O(n^2logn))的方法,显然无论是(gcd)还是(or)都有连续位置答案是一定的
考虑每次在后面加入一个数后,从1开始更新(gcd)和(or),如果遇到(gcd)或者(or)相同的一段,用链表将其合并
如果(gcd)下一个位置在(or)下一个位置之前那么跳到下一个(gcd),否则跳到下一个(or),我不会证明,但是时间复杂度应该是(O(nlogn))
代码
#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
const int N=500011; long long ans;
int Gcd[N],Or[N],a[N],n,k,Guf[N],Gre[N],Ouf[N],Ore[N];
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline signed min(int a,int b){return a<b?a:b;}
inline signed gcd(int a,int b){return !b?a:gcd(b,a%b);}
inline void doit(int ed){
for (rr int st=1;st<=ed;){
Gcd[st]=gcd(Gcd[st],a[ed]),Or[st]|=a[ed];
if (Gcd[st]==(Or[st]^k)) ans+=min(Guf[st],Ouf[st])-st;//这一段都是答案
if (Gcd[st]==Gcd[Gre[st]]) Guf[Gre[st]]=Guf[st],Gre[Guf[st]]=Gre[st];//gcd相等合并
if (Or[st]==Or[Ore[st]]) Ouf[Ore[st]]=Ouf[st],Ore[Ouf[st]]=Ore[st];//or相等合并
if (Guf[st]<Ouf[st]) Or[Guf[st]]=Or[st],Ouf[Guf[st]]=Ouf[st],Ore[Guf[st]]=Ore[st];//先把原先合并的段拆成两部分
if (Guf[st]>Ouf[st]) Gcd[Ouf[st]]=Gcd[st],Guf[Ouf[st]]=Guf[st],Gre[Ouf[st]]=Gre[st];//同上
st=min(Guf[st],Ouf[st]);//跳到下一个
}
}
signed main(){
n=iut(),k=iut();
for (rr int i=1;i<=n;++i) Gcd[i]=Or[i]=a[i]=iut();
for (rr int i=1;i<=n;++i) Gre[i]=Ore[i]=i-1,Guf[i]=Ouf[i]=i+1;//链表
for (rr int i=1;i<=n;++i) doit(i);
return !printf("%lld",ans);
}