Codeforces Round 845 (Div. 2) and ByteRace 2023(C. Quiz Master)

传送门

题意:

多组询问,一个长为 n 的数列 a 和一个数 m,求在数列 a 中删掉几个数,使得从 1到 m 的所有数组成的集合是数列 a 中所有数的因数组成的集合的子集,求删数后数列 a 的极差。

思路:

考虑对 a 序列从小到大排序。可以发现,一定存在一种最优方案,使得选出的数在 a 排序后的序列中是一段连续区间,且极差最小。因为如果存在一种最优方案选取的不是连续区间,那么将这些数最左端和最右端内全部选取,仍然符合题意,极差不变,但是选择的数是连续区间。

因此将 a 排序后,考虑双指针,因此我们只需要维护一段连续区间是否符合题意。

AC代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+10;
int a[N],cnt[N];
vector<int>f[N];
set<int>s;
void solve(){
	int n,k;
	cin>>n>>k;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		f[i].clear(); 
	}
	s.clear();
	sort(a+1,a+n+1);
	for(int i=1;i<=n;i++){
		int x=a[i];
		for(int j=1;j*j<=x;j++){
			if(x%j==0){
				f[i].push_back(j);
				if(j*j!=x){
					f[i].push_back(x/j);
				}	
			} 
		}
	}
	for(int i=1;i<=k;i++){
		s.insert(i);
		cnt[i]=0;
	}
	int l=1,r=0,ans=1e9;
	int flag=0;
	while(l<=n&&r<=n){
		if(flag==0){
			r++;
			if(r>n) break;
			for(auto j:f[r]){
				if(j<=k){
					cnt[j]++;
					if(cnt[j]==1){
						s.erase(j);
					}
				}
			}
			if(s.size()==0){
				ans=min(ans,a[r]-a[l]);
				flag=1;
			}
		}
		else {
			if(l>n) break;
			for(auto j:f[l]){
				if(j<=k){
					cnt[j]--;
					if(cnt[j]==0){
						s.insert(j);
					}
				}
			}
			if(s.size()==0){
				ans=min(ans,a[r]-a[l+1]);
			}
			else flag=0;
			l++;
		}
	}
	if(ans==1e9) ans=-1;
	cout<<ans<<"\n";
}
signed main(){
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	int t;
	cin>>t;
	while(t--){
		solve();
	}
} 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值