P3794 签到题IV 题解

题目传送门

前置知识

最大公约数

解法

\(\gcd\)\(\operatorname{or}\) 在固定左端点的情况下至多会变化 \(O(\log V)\) 次。

\(\gcd\) 为例,考虑求出所有的四元组 \((l,r,x,val)\) 表示 \(\forall i \in [l,r],\gcd\limits_{j=i}^{x} \{ a_{j} \}=val\)

  • 本题中因为 \(x\) 一维可以“滚”掉,所以省去不写。

具体地,枚举右端点 \(x\),类似单调栈的写法(本身是单调的),继承 \(x-1\) 的四元组并及时去重/重构栈。

处理完后判断一下每个值区间是否有交求贡献即可。

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define ull unsigned long long
#define sort stable_sort 
#define endl '\n'
struct  node
{
	ll val,l,r;
}g[500010],o[500010];
ll a[500010],l[500010],r[500010],cnt_g,cnt_o;
ll gcd(ll a,ll b)
{
	return b?gcd(b,a%b):a;
}
int main()
{
	ll n,k,ans=0,len,i,j;
	cin>>n>>k;
	for(i=1;i<=n;i++)
	{
		cin>>a[i];
	}
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=cnt_g;j++)
		{
			g[j].val=gcd(g[j].val,a[i]);
		}
		cnt_g++;
		g[cnt_g]=(node){a[i],i,i};
		len=0;
		for(j=1;j<=cnt_g;j++)
		{
			if(g[j].val==g[j-1].val)
			{
				g[len].r=g[j].r;
			}
			else
			{
				len++;
				g[len]=g[j];
			}
		}
		cnt_g=len;
		for(j=1;j<=cnt_g;j++)
		{
			l[g[j].val]=g[j].l;
			r[g[j].val]=g[j].r;
		}
		for(j=1;j<=cnt_o;j++)
		{
			o[j].val|=a[i];
		}
		cnt_o++;
		o[cnt_o]=(node){a[i],i,i};
		len=0;
		for(j=1;j<=cnt_o;j++)
		{
			if(o[j].val==o[j-1].val)
			{
				o[len].r=o[j].r;
			}
			else
			{
				len++;
				o[len]=o[j];
			}
		}
		cnt_o=len;
		for(j=1;j<=cnt_o;j++)
		{
			if(l[o[j].val^k]!=0&&min(o[j].r,r[o[j].val^k])>=max(o[j].l,l[o[j].val^k]))
			{
				ans+=min(o[j].r,r[o[j].val^k])-max(o[j].l,l[o[j].val^k])+1;
			}
		}
		for(j=1;j<=cnt_g;j++)
		{
			l[g[j].val]=r[g[j].val]=0;
		}
	}
	cout<<ans<<endl;
	return 0;
}
posted @ 2024-10-16 11:17  hzoi_Shadow  阅读(30)  评论(2编辑  收藏  举报
扩大
缩小