题目链接:
题意:
给定数组a,构造一个数组p,pi不超过k,使得:
达到最小值,求这个最小值。
两题仅数据量不同。
———————————————————————————————————————————
考虑最小值的范围肯定在0~a[0]之间,枚举最小值,让其他的尽量靠近最小值。每一个枚举最小值都可以得到一个拟定最优解,求这些解的最小值即可。
时间复杂度为O(t*n*n),可以过D1。
CODE:
#include<bits/stdc++.h>
using namespace std;
const int N=3010;
int a[N];
int main()
{
int t;
cin>>t;
while(t--){
int n,k;
cin>>n>>k;
for(int i=0;i<n;++i) cin>>a[i];
int ans=INT_MAX;
for(int i=0;i<=a[0];++i){
int res=0,p;
for(int j=0;j<n;++j){
if(i) p=min(k,a[j]/i);
else p=k;
res=max(res,abs(a[j]/p-i));
}
ans=min(ans,res);
}
cout<<ans<<endl;
}
return 0;
}
对上述代码进行优化:题目保证a是增序列,还是枚举最小值,对循环第二层优化。如果最小值是0,答案可以直接求出。
对于非零最小值为i的情况,上一次是直接枚举整个序列求最大差值。现在我们枚举a[j]/i的可能值j,这样有限制条件j*i<=a[n-1],对于j=a[p]/i,a[p]=i*j,因此可以用二分查找的方式确定a[p]。
CODE:
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int a[N],p[N];
int main()
{
int t;
cin>>t;
while(t--){
int n,k;
cin>>n>>k;
for(int i=0;i<n;++i) scanf("%d",&a[i]);
int ans=INT_MAX;
for(int i=0;i<=a[0];++i){
int res=0,p;
if(!i) res=a[n-1]/k;
else{
for(int j=1;1ll*j*i<=a[n-1];++j){
p=lower_bound(a,a+n,i*(j+1))-a-1;
if(p>=0&&a[p]/i==j) res=max(res,a[p]/min(k,a[p]/i)-i);
}
}
ans=min(ans,res);
}
cout<<ans<<endl;
}
return 0;
}