B
1800
题意
给出一个含 n n n 个数的序列 a 1 , a 2 , . . . , a n a_1,a_2,...,a_n a1,a2,...,an,并给出 c c c ,表示序列中所有数大小都不超过 c c c。我们称序列是整的当且仅当对于序列中任意两个(或同一个)数 x , y ( x ≤ y ) x,y(x\leq y) x,y(x≤y) , 满足 ⌊ y x ⌋ \lfloor \frac yx\rfloor ⌊xy⌋ 也在序列中。问这个序列是否是整的。 ( n ≤ 1 e 6 ) (n\leq1e6) (n≤1e6)
思路
这种题第一反应就是用类似素数筛的方法去优化,把对
r
=
⌊
y
x
⌋
r=\lfloor \frac yx\rfloor
r=⌊xy⌋ 的判断改成对
y
y
y 的判断,不能拆成
x
和
r
x和r
x和r ”,所以可以枚举所有的
x
x
x,并枚举所有
r
∉
a
r\notin a
r∈/a , 如果在
x
×
r
x\times r
x×r 对应的范围内存在
y
y
y,则
r
=
⌊
y
x
⌋
∉
a
r=\lfloor \frac yx\rfloor\notin a
r=⌊xy⌋∈/a ,不是整的。对应的范围即为
[
r
×
x
,
r
×
x
+
x
−
1
]
[r\times x,r\times x + x - 1]
[r×x,r×x+x−1],是否存在
y
y
y 只要预处理前缀和就可以了。
由调和级数,时间复杂度
O
(
c
log
c
)
O(c\log c)
O(clogc) 。
代码
int cnt[maxn], sum[maxn];
void solve() {
int n, c;
cin >> n >> c;
for(int i = 1; i <= c; i++) cnt[i] = 0;
for(int i = 1; i <= n; i++) {
int x;
cin >> x;
cnt[x]++;
}
sum[0] = 0;
for(int i = 1; i <= c; i++) {
sum[i] = sum[i-1] + cnt[i];
}
for(int x = 1; x <= c; x++) {
if(!cnt[y]) {
continue;
}
for(int i = 1; i * x <= c; i++) {
if(cnt[i]) continue;
int l = i * x - 1;
int r = min((i+1)*x-1, c);
if(sum[r] - sum[l]) {
cout << "No\n";
return;
}
}
}
cout << "Yes\n";
}