题目大意:
题目链接:https://loj.ac/problem/2685
思路:
显然离线。
设
f
[
x
]
f[x]
f[x]表示人数为
x
x
x时的答案。可以证明
f
[
x
]
f[x]
f[x]为单调递增的。
对于一个答案相同的区间
[
x
,
y
]
[x,y]
[x,y],设
x
x
x的在给定集合里的最大质因子为
p
p
p,则显然
x
∼
x
+
p
−
1
x\sim x+p-1
x∼x+p−1的答案与
x
x
x相同。因为
g
c
d
(
x
+
p
,
x
)
=
p
gcd(x+p,x)=p
gcd(x+p,x)=p,所以
a
n
s
[
x
+
p
]
=
a
n
s
[
x
]
+
1
ans[x+p]=ans[x]+1
ans[x+p]=ans[x]+1,然后
a
n
s
[
x
]
≤
a
n
s
[
x
+
p
−
1
]
<
a
n
s
[
x
+
p
]
ans[x]\leq ans[x+p-1]<ans[x+p]
ans[x]≤ans[x+p−1]<ans[x+p]。
所以预处理出关于每一个
x
x
x的
p
p
p(复杂度
O
(
m
a
x
n
log
log
n
)
O(maxn\log \log n)
O(maxnloglogn)),然后就可以
O
(
m
)
O(m)
O(m)直接回答了。
代码:
#include <queue>
#include <cstdio>
#include <string>
using namespace std;
const int N=10000010;
int n,m,x,maxn,p[N],v[N],ask[N],ans[N];
queue<int> q;
int read()
{
int d=0;
char ch=getchar();
while (!isdigit(ch)) ch=getchar();
while (isdigit(ch))
d=(d<<3)+(d<<1)+ch-48,ch=getchar();
return d;
}
int main()
{
n=read(); m=read();
for (int i=1;i<=n;i++)
p[i]=read();
for (int i=1;i<=m;i++)
{
ask[i]=read();
if (ask[i]>maxn) maxn=ask[i];
}
for (int i=1;i<=n;i++)
for (int j=p[i];j<=maxn;j+=p[i])
v[j]=p[i];
v[0]=p[n];
q.push(0);
for (int i=1;q.size()&&i<=maxn;)
{
x=q.front();
q.pop();
if (v[x])
for (;i<x+v[x] && i<=maxn;i++)
{
ans[i]=ans[x]+1;
q.push(i);
}
}
for (int i=1;i<=m;i++)
if (ans[ask[i]] || !ask[i]) printf("%d\n",ans[ask[i]]);
else printf("oo\n");
return 0;
}