CF1706D2

· · 题解

解题思路:

D1:

首先预处理出来每个数字 $a_i$ 当 $p\in[1,k]$ 时 $\lfloor \frac{a_i}{p}\rfloor$ 能取到的值。 然后枚举最大值,再用二分找到对于每个 $i$ 的最接近但比枚举到的最大值小的 $\lfloor \frac{a_i}{p}\rfloor$,记为 $w_i$,取所有 $w_i$ 的最小值即可,最后的答案就是最小的最大值减最小值。 #### 代码: ```cpp #include<cstdio> #include<algorithm> #include<cstring> #define rep(x,y,z) for(int x=y;x<=z;x++) #define per(x,y,z) for(int x=z;x>=y;x--) using namespace std; const int N=3000+10; int a[N],te[N][N]; int main() { int T; scanf("%d",&T); while(T--) { memset(te,0,sizeof(te)); int n,k; scanf("%d%d",&n,&k); rep(i,1,n) scanf("%d",&a[i]); rep(i,1,n) per(j,1,k) te[i][++te[i][0]]=a[i]/j; int ans=1e9; rep(i,1,3000) { bool f=1; int mmin=1e9; rep(j,1,n) { int pos=upper_bound(te[j]+1,te[j]+1+te[j][0],i)-te[j]-1; if(pos==0) {f=0;break;} mmin=min(mmin,te[j][pos]); } if(f) ans=min(ans,i-mmin); } printf("%d\n",ans); } return 0; } ``` ### D2: $n,k\le100000$,$n^2$ 肯定不太行。 观察到预处理部分可以用数论分块把时间优化到 $O(n\sqrt{n})$。 但如果把所有的 $\lfloor \frac{a_i}{p}\rfloor$ 可能的取值都存下来空间会炸,实际上我们只关心比一个数小的最大数。 对于每个 $i$,首先得到 $\lfloor \frac{a_i}{p}\rfloor$ 可能的取值,记录在 $te$ 中,然后排序,执行: ```cpp rep(j,1,tot) mx[te[j]]=max(mx[te[j]],te[j+1]); ``` $te_{j+1}$ 就是 $te$ 中比 $tr_j$ 大的最小数,$mx$ 是全局数组。 求答案: ```cpp rep(i,0,100000) { ans=min(ans,mmax-i); mmax=max(mmax,mx[i]); } ``` 首先 $mmax$ 一定大于等于 $i$,因为 $mmax\ge mx_{i-1}$,而 $mx_{i-1}>i-1$,所以 $mmax\ge i$。 其次 $mmax$ 一定是能取到的大于等于 $i$ 的数中最小的。 #### 代码: ``` #include<cstdio> #include<algorithm> #include<cstring> #include<vector> #define rep(x,y,z) for(int x=y;x<=z;x++) #define per(x,y,z) for(int x=z;x>=y;x--) using namespace std; const int N=1e5+10; void R(int &x) { x=0; char ch=getchar(); while(ch<'0'||ch>'9') ch=getchar(); while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); } int a[N],te[N],mx[N]; inline int get(int l,int n) { return n/(n/l); } int main() { int T; scanf("%d",&T); while(T--) { memset(mx,0,sizeof(mx)); int n,k,mmax=0; R(n),R(k); rep(i,1,n) R(a[i]); rep(i,1,n) { int tot=0; for(int l=1,r=0;l<=min(k,a[i]);l=r+1) { r=get(l,a[i]); te[++tot]=a[i]/l; } if(k>a[i]) te[++tot]=0; reverse(te+1,te+1+tot); mmax=max(mmax,te[1]); te[tot+1]=1e9; rep(j,1,tot) mx[te[j]]=max(mx[te[j]],te[j+1]); } int ans=1e9; rep(i,0,100000) { ans=min(ans,mmax-i); mmax=max(mmax,mx[i]); } printf("%d\n",ans); } return 0; } ```