#链表#洛谷 3794 签到题IV

题目

给出一个长度为\(n\)的数列\(a\),求

\[\sum_{i=1}^n\sum_{j=i}^n[\gcd(a_{i\sim j})\;xor\;or(a_{i\sim 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);
}
posted @ 2020-08-19 07:58  lemondinosaur  阅读(115)  评论(0编辑  收藏  举报