AtCoder Regular Contest 141 D,E

D
很有趣的一题。

首先注意到一个不同寻常的条件\(M\leq N\leq 2M\),这启发我们去想有关奇偶的结论。

我们将每个数剖开所有\(2\)的因子,即\(a_{i}=b_{i}2^{c_{i}}\),其中\(b_{i}\)是奇数。比如\(a_{i}=12=3\times 2^2\),此时\(b_{i}=3,c_{i}=2\)

那么若对于\(i,j\),且\(i\neq j\)\(b_{i}=b_{j}\),那么我们只能选择其中的一个。(因为它们互为倍数)

也就是,对于每个\(b\),我们只能选择一个,而我们现在最少要选择\(\frac{n}{2}\)个(\(N\leq 2M\)),且\(b\)最大也就\(2M-1\)\(a_{i}\leq 2M\))。所以对于每个不同的\(b\),我们必须从中选择一个

如果对于奇数\(i\)满足\(1\leq i\leq 2M\),且没有任何一个\(j\),满足\(b_{j}=i\),那无论如何我们都选择不了\(M\)个,所以全部输出\(No\)

但注意,比如像\(b_{i}=1\)\(b_{j}=3\)之间也可能出现倍数关系(比如\(2\)\(6\)),这里,若\(b_{i}<b_{j}\),且\(b_{i}\)\(b_{j}\)的因子,那么\(c_{j}\)必须小于\(c_{i}\),。(比如我们不能选择\(2\)\(6\),因为\(c_{i}=1,c_{j}=1\);而我们可以选择\(4\)\(6\),因为\(c_{i}=2,c_{j}=1\)

那么我们就可以根据倍数关系建图,进行拓扑排序,得到当\(b=i\)\(c_{i}\)的取值范围(最大值和最小值)。如果有任何一个\(b=i\)\(c_{i}\)的取值范围是空的话(即最小取值大于最大取值),意味着\(b=i\)时我们没法选择,此时也全部输出\(No\)

否则我们就判断\(c_{i}\)是否在\(b_{i}\)时的取值范围内部,输出\(Yes\)\(No\)

时间复杂度为\(O(n\log n)\)

#include<bits/stdc++.h>
#define debug(...) std::cerr<<#__VA_ARGS__<<" : "<<__VA_ARGS__<<std::endl

const int maxn=600005;
int n,m;
int a[maxn],pw[maxn];
int mx[maxn],in[maxn];
int mn[maxn],rin[maxn];
std::vector<int> vec[maxn],g[maxn],rg[maxn];

int main() {
	scanf("%d%d",&n,&m);
	for(int i=1,num;i<=n;i++) {
		scanf("%d",&a[i]);
		pw[i]=1,num=a[i];
		while(num%2==0) num/=2,pw[i]+=pw[i];
		vec[a[i]/pw[i]].push_back(pw[i]);
	}
	for(int i=1;i<=m+m;i+=2) {
		if(vec[i].empty()) {
			for(int i=1;i<=n;i++) printf("No\n");
			exit(0);
		}
		std::sort(vec[i].begin(),vec[i].end());
	}
	for(int i=1;i<=m+m;i++) {
		for(int j=i+i;j<=m+m;j+=i) {
			//从i连向一个通往j的边
			if(i%2==0||j%2==0) continue;//下标只能是奇数 
			g[i].push_back(j); in[j]++;
			rg[j].push_back(i); rin[i]++;
		}
	}
	std::queue<int> q;
	for(int i=1;i<=m+m;i+=2) {
		mx[i]=vec[i].back();
		if(!in[i]) q.push(i);
	}
	while(!q.empty()) {
		int pos=q.front(); q.pop();
		for(auto to : g[pos]) {
			int p=std::lower_bound(vec[to].begin(),vec[to].end(),mx[pos])-vec[to].begin()-1;
			if(p>=0) {
				mx[to]=std::min(mx[to],vec[to][p]);
			} else {
				mx[to]=-1;//impossible
			}
			in[to]--;
			if(!in[to]) q.push(to);
		}
	}
	for(int i=1;i<=m+m;i+=2) {
		mn[i]=vec[i][0];
		if(!rin[i]) q.push(i);
	}
	while(!q.empty()) {
		int pos=q.front(); q.pop();
		for(auto to : rg[pos]) {
			int p=std::upper_bound(vec[to].begin(),vec[to].end(),mn[pos])-vec[to].begin();
			if(p>=vec[to].size()) {
				mn[to]=1e9;
			} else {
				mn[to]=std::max(mn[to],vec[to][p]);
			}
			rin[to]--;
			if(!rin[to]) q.push(to);
		}
	}
	for(int i=1;i<=m+m;i+=2) {
		if(mn[i]==1e9||mx[i]==-1) {
			for(int j=1;j<=n;j++) printf("No\n");
			exit(0);
		}
	} 
	for(int i=1;i<=n;i++) {
		int ind=a[i]/pw[i];
		if(mn[ind]<=pw[i]&&pw[i]<=mx[ind]) {
			printf("Yes\n");
		} else {
			printf("No\n");
		}
	}
	return 0;
}
/*
6 6 
4 5 12 7 9 11
*/
posted @ 2022-06-02 16:35  Nastia  阅读(41)  评论(0)    收藏  举报