[ARC141D] Non-divisible Set

[ARC141D] Non-divisible Set

我们认为 \(n,m\) 同阶。

看起来很像一道小学奥数题,当时我们证明了 \(\{1,2,\dots,2m\}\) 的最大好子集大小为 \(m\)。

考虑当时的做法,我们将 \(x\) 拆分成 \(2^a \times b\),其中 \(b\) 是奇数。

容易发现,这个过程对于所有的 \(b\) 形成了一个类,且一个类内必须选择恰好一个数。

考虑两个不同类的数 \(2^a \times b \mid 2^c \times d\) 的条件:

  • \(a \leq c\)

  • \(b \mid d\)

对于不整除的情况无需考虑,对于 \(b \mid d\),我们一定需要让 \(a > c\)。

于是我们得到了 \(O(n^2)\) 的做法,考虑优化。

我们考虑对于每个 \(b\),求出合法的 \(a\) 范围,这是容易 dp 的。

接下来我们只要判断是否在范围内即可,复杂度 \(O(n \log n)\)。

//Ad astra per aspera
#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
vector<int> lst[600010];
int a[600010],b[600010],c[600010],l[600010],r[600010];
vector<int> yinshu[600010],beishu[6000010]; 
int main(){
	int n,m;
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		b[i]=0;
		c[i]=a[i];
		while(c[i]%2==0){
			b[i]++;
			c[i]>>=1;
		}
		lst[c[i]].push_back(b[i]);
	}
	for(int i=1;i<=2*m-1;i+=2){
		for(int j=3*i;j<=2*m;j+=2*i){
			yinshu[j].push_back(i);
			beishu[i].push_back(j);
		}
	}
	for(int i=1;i<=2*m-1;i+=2){
		int minn=0x3f3f3f3f;
		for(int j=0;j<yinshu[i].size();j++){
			int k=yinshu[i][j];
			minn=min(minn,r[k]);
		}
		vector<int> :: iterator iter=lower_bound(lst[i].begin(),lst[i].end(),minn);
		if(iter==lst[i].begin()){
			r[i]=-0x3f3f3f3f;
		}
		else{
			iter--;
			r[i]=*iter;
		}
	}
	for(int i=2*m-1;i>=1;i-=2){
		int maxn=-0x3f3f3f3f;
		for(int j=0;j<beishu[i].size();j++){
			int k=beishu[i][j];
			maxn=max(maxn,l[k]);
		}
		vector<int> :: iterator iter=upper_bound(lst[i].begin(),lst[i].end(),maxn);
		if(iter==lst[i].end()){
			l[i]=0x3f3f3f3f;
		}
		else{
			l[i]=*iter;
		}
	}
	for(int i=1;i<=2*m-1;i+=2){
		if(l[i]>r[i]){
			for(int j=1;j<=n;j++){
				printf("No\n"); 
			}
			return 0;
		}
	}
	for(int i=1;i<=n;i++){
		if(b[i]>=l[c[i]]  &&  b[i]<=r[c[i]]){
			printf("Yes\n");
		}
		else{
			printf("No\n");
		}
	}
	return 0;
}
posted @ 2026-03-23 14:10  Oken喵~  阅读(21)  评论(0)    收藏  举报