2017 USP Try-outs C. Coprimes
Posted solemntee
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2017 USP Try-outs C. Coprimes相关的知识,希望对你有一定的参考价值。
传送门:Coprimes
题意:给你一个长度为
n
n
n的数组,问
l
l
l到
r
r
r位置间是否有互素对
(
a
[
i
]
,
a
[
j
]
)
=
1
(
i
≠
j
)
(a[i],a[j])=1(i\\not=j)
(a[i],a[j])=1(i=j)
对于每个位置
l
l
l,我们可以求出最小的
r
r
r,使得
[
l
,
r
]
[l,r]
[l,r]之间有互质的数对。
随着
l
l
l的增大,
r
r
r一定会增大,因此我们可以考虑尺取。在右端点进入和左端点退出的时候,我们尝试维护区间内不互质数对的个数
p
a
i
r
pair
pair。
对于
μ
(
x
)
≠
0
μ(x)≠0
μ(x)=0的
x
x
x,我们用
c
n
t
[
x
]
cnt[x]
cnt[x]维护,区间内有多少个数字的因子中有
x
x
x,然后,没进入一个右端点
r
r
r时,那么每个
d
∣
a
[
r
]
d|a[r]
d∣a[r]且
μ
(
d
)
≠
0
μ(d)≠0
μ(d)=0且
d
≠
1
d≠1
d=1的
d
d
d对
p
a
i
r
pair
pair的贡献为
−
μ
(
d
)
c
n
t
[
d
]
−μ(d)cnt[d]
−μ(d)cnt[d],把这个贡献加到
p
a
i
r
pair
pair里去,同理,退出一个又端点的时候,把这个贡献从
p
a
i
r
pair
pair中减去。
简而言之,构建一个桶,
c
n
t
[
x
]
cnt[x]
cnt[x]来维护集合中
x
x
x倍数的数量,那么集合中与
a
[
x
]
a[x]
a[x]不互素的数数量等于
∑
d
∣
a
[
i
]
,
d
≠
1
−
μ
(
d
)
c
n
t
[
d
]
\\sum_{d|a[i],d\\not=1} -μ(d)cnt[d]
d∣a[i],d=1∑−μ(d)cnt[d]
因为1不能作为公因数所以容斥
c
n
t
[
1
]
cnt[1]
cnt[1]没有意义,我们跳过1,后面所有的数字就都要取反
#include<bits/stdc++.h>
using namespace std;
int nxt[500005];
bool vis[10000005];
int pri[1000005];
int mo[1000005];
int tot=0;
void init(int n)
{
memset(vis,0,sizeof(vis));
mo[1]=1;
for(int i=2;i<=n;i++)
{
if(!vis[i])pri[++tot]=i,mo[i]=-1;
for(int j=1;j<=tot&&pri[j]*i<=n;j++)
{
vis[i*pri[j]]=1;
if(i%pri[j]==0)
{
mo[i*pri[j]]=0;
break;
}
else mo[i*pri[j]]=mo[i]*-1;
}
}
}
int nowans=0;
int CNT[500005];
int a[500005];
void addcnt(int id,int w)
{
for(int i=1;i*i<=a[id];i++)
{
if(a[id]%i==0)
{
if(i*i==a[id])CNT[i]+=w;
else
{
CNT[i]+=w;
CNT[a[id]/i]+=w;
}
}
}
}
void add(int id,int w)
{
for(int i=1;i*i<=a[id];i++)
{
if(a[id]%i==0)
{
if(i*i==a[id])
{
nowans+=mo[i]*w*CNT[i];
}
else
{
nowans+=mo[i]*w*CNT[i];
nowans+=mo[a[id]/i]*w*CNT[a[id]/i];
}
}
}
}
int main()
{
init(500000);
mo[1]=0;
int N,M;
scanf("%d%d",&N,&M);
for(int i=1;i<=N;i++)scanf("%d",&a[i]);
int R=0;
for(int l=1;l<=N;l++)
{
while(nowans<=0&&R<N)
{
add(++R,1);
addcnt(R,1);
nowans+=R-l;
}
if(nowans>0)nxt[l]=R;
else nxt[l]=-1;
nowans-=R-l;
addcnt(l,-1);
add(l,-1);
}
for(int i=1;i<=M;i++)
{
int l,r;
scanf("%d%d",&l,&r);
if(nxt[l]!=-1&&nxt[l]<=r)printf("S\\n");
else printf("N\\n");
}
return 0;
}
以上是关于2017 USP Try-outs C. Coprimes的主要内容,如果未能解决你的问题,请参考以下文章
Gym .101879 USP Try-outs (寒假自训第七场)
IME Starters Try-outs 2018 J. JHADCBEIGF