前置知识
解法
\(\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;
}
标签:gcd,val,签到,题解,ll,long,P3794,500010,define
From: https://www.cnblogs.com/The-Shadow-Dragon/p/18469438