NOIP2024模拟赛7:纯粹当下

NOIP2024模拟赛7:纯粹当下

今日挂分:95pts......

T2

  • \(T\) 组数据, 每组给定 \(n,k,f,a_i\), 一个序列 \(b\) 满足 \(b_i \in [a_i-k,a_i]\), 记 \(g\) 表示至多删去序列中 \(f\) 个数后, 使得剩余所有数的 \(\gcd\), 求 \(g\) 的集合并输出.
  • 标签:转化,调和级数,前缀和.
  • 其实也有点儿 逆向思维 的感觉...
  • 直接枚举 \(g\), 考虑 b 的集合就是 \({b \ | \ b=c\times}g,c \in \N^+\)
  • 那么就反过来检测有多少个不合法的 \(a_i\)
  • 反过来, \(a_i\) 的 范围就变成了 \([c\times g,c\times g+k],c \in \N^+\)
  • 此范围以外的 \(a_i\) 都是不合法的,要求其个数不超过 \(f\).
  • 关于个数的统计,开个桶做个前缀和即可.
  • 时间复杂度: \(O(n\ln_n)\)
  • 总结一下: 其思维的逆向在于:本来 \(b_i\) 的取值是不定的,但由于 \(gcd\) 的条件因此反而需要 \(a_i\) 的取值来 "配合" \(b_i\) 的取值.
#include<bits/stdc++.h>
#define F(i,l,r) for(int i(l);i<=r;++i)
#define G(i,r,l) for(int i(r);i>=l;--i)
using namespace std;
using ll = long long;
char buf[100],*p1=buf,*p2=buf,obuf[10000000],*o=obuf;
inline int gc(){return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100,stdin),p1==p2)?EOF:*p1++;}
inline int rd(){
	int x=0; char ch;
	while(!isdigit(ch=gc()));
	do x=(x<<3)+(x<<1)+(ch^48); while(isdigit(ch=gc()));
	return x;
}
inline void write(int x){
	if(x>9) write(x/10);
	*o++=(x%10+48);
} 
const int N=2e6+5;
int n,k,f,T,mx=0,cnt=0;
int sum[N];
signed main(){
//	freopen("tsuki.in","r",stdin);
//	freopen("tsuki.out","w",stdout);
	T=rd(); while(T--){
		n=rd(),k=rd(),f=rd();
		mx=0;
		memset(sum,0,sizeof(sum));
		F(i,1,n){
			int x=rd();
			sum[x]++;
			mx=max(mx,x);
		}
		F(i,1,mx) sum[i]+=sum[i-1];
		write(1); *o++=' ';
		F(g,2,mx){
			cnt=sum[g-1];
			for(int i=g;i<=mx && i+k<mx;i+=g){
				int l=i+k+1,r=min(mx,i+g-1);
				if(l<=r) cnt+=sum[r]-sum[l-1];
			}
			if(cnt<=f) write(g),*o++=' ';
		}
		*o++='\n';
	}
	fwrite(obuf,o-obuf,1,stdout);
	return fclose(stdin),fclose(stdout),fflush(0),0;
}
posted @ 2024-05-17 21:05  superl61  阅读(3)  评论(0编辑  收藏  举报