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;
}
标签:p1,int,sum,rd,NOIP2024,纯粹,buf,mx,模拟
From: https://www.cnblogs.com/superl61/p/18198716