题目链接
题目解法
神仙题!
考虑到
a
i
<
2
m
a_i<2m
ai<2m 的奇怪限制,可以得到对于
k
∗
2
i
(
k
k*2^i(k
k∗2i(k 为奇数
)
)
) 的形式的所有数中,只能选出
1
1
1 个,且必须选出一个,因为
1
−
2
m
1-2m
1−2m 的奇数只有
m
m
m 个
考虑满足条件的形式是什么,即对于
k
1
∗
2
i
,
k
2
∗
2
j
k_1*2^i,k_2*2^j
k1∗2i,k2∗2j,不存在
i
<
j
i<j
i<j 且
k
1
<
k
2
k1<k2
k1<k2
这启发我们对每个
i
i
i 算出符合条件
k
k
k 的区间范围
L
k
,
R
k
L_k,R_k
Lk,Rk(确实有数的出现的范围)
具体如何求解
L
k
,
R
k
L_k,R_k
Lk,Rk?这里以
L
k
L_k
Lk 举例,只要从大到小枚举
k
k
k,然后
L
k
=
max
{
L
d
+
1
}
(
k
∣
d
)
L_k=\max\{L_d+1\}(k|d)
Lk=max{Ld+1}(k∣d)
然后把
a
i
a_i
ai 查封成
k
∗
2
i
k*2^i
k∗2i 的形式,易知当
L
[
i
]
≤
k
≤
R
[
i
]
L[i]\le k\le R[i]
L[i]≤k≤R[i] 的时候是有解的,否则无解(还有一些无解条件是不能得到所有的奇数
k
k
k 或者
L
k
>
R
k
L_k>R_k
Lk>Rk)
时间复杂度
O
(
n
ln
n
)
O(n\ln n)
O(nlnn)
#include <bits/stdc++.h>
using namespace std;
const int N=1000100;
int n,m,a[N],L[N],R[N];
bool vis[N];
inline int read(){
int FF=0,RR=1;
char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
return FF*RR;
}
int find(int x){
for(int i=0,bs=1;;i++,bs<<=1) if(bs>x) return i-1;
}
int ed(){
for(int i=1;i<=n;i++) puts("No");
exit(0);
}
int main(){
n=read(),m=read();
for(int i=1;i<=n;i++) a[i]=read(),vis[a[i]]=1;
for(int i=1;i<=m<<1;i+=2){
bool flg=0;
for(int j=i;j<=m<<1;j<<=1) if(vis[j]){ flg=1;break;}
if(!flg) ed();
}
for(int i=1;i<=m<<1;i+=2) R[i]=find((m<<1)/i);
for(int i=1;i<=m<<1;i+=2){
while(R[i]>=0&&!vis[i<<R[i]]) R[i]--;
for(int j=3*i;j<=m<<1;j+=i<<1) R[j]=min(R[j],R[i]-1);
}
for(int i=(m<<1)-1;i>=1;i-=2){
for(int j=3*i;j<=m<<1;j+=i<<1) L[i]=max(L[i],L[j]+1);
while((i<<L[i])<=(m<<1)&&!vis[i<<L[i]]) L[i]++;
}
for(int i=1;i<=m<<1;i+=2) if(L[i]>R[i]) ed();
for(int i=1;i<=n;i++){
int k=0;
while(~a[i]&1) a[i]>>=1,k++;
if(L[a[i]]<=k&&k<=R[a[i]]) puts("Yes");
else puts("No");
}
fprintf(stderr,"%d ms\n",int(1e3*clock()/CLOCKS_PER_SEC));
return 0;
}