题意:给定长度为n的数组a,数组p长度为n且其中每个元素可在[1,k]间取整数。求
m
a
x
i
⌊
a
i
/
p
i
⌋
−
m
i
n
i
⌊
a
i
/
p
i
⌋
max_i\lfloor a_i/p_i \rfloor - min_i\lfloor a_i/p_i \rfloor
maxi⌊ai/pi⌋−mini⌊ai/pi⌋的最小值。
数据范围:
1
≤
k
,
n
≤
3000
1 \leq k,n \leq 3000
1≤k,n≤3000,
1
≤
a
1
≤
a
2
⋯
a
n
≤
3000
1 \leq a_1 \leq a_2 \cdots a_n \leq 3000
1≤a1≤a2⋯an≤3000
超时的思路:对每个i预处理能够达到的数。遍历每个i考察可以达到的数并假设其为最大值,对其他所有j!=i求最后一个小于等于该值的数。
#include
using namespace std;
typedef long long ll;
const ll mod = 998244353;
int main()
{
int t; cin>>t;
for(int i =0 ;i<t;i++)
{
int n,k;scanf("%d%d",&n,&k);
int a[n];for(int o = 0;o<n;o++)scanf("%d",&a[o]);
if(k > a[n-1] || n == 1)printf("0\n");
else
{
vector<int> m[n];
for(int i = 0;i<n;i++) for(int j = k;j>=1;j--) if(m[i].size()==0||a[i]/j>m[i][m[i].size()-1])m[i].push_back(a[i]/j);
int ans = INT_MAX;
for(int i = 0;i<n;i++)
{
for(int v:m[i])
{
int maximal = v;
int minmax = INT_MAX;
bool f = true;
for(int j = 0;j<n;j++)
{
if(i!=j)
{
auto iter = upper_bound(m[j].begin(),m[j].end(),v);
iter = prev(iter);
if(iter-m[j].begin()>=0) minmax=min(minmax,*iter); else {f=false;break;}
}
}
if(f)ans = min(ans,maximal - minmax);
}
}
printf("%d\n",ans);
}
}
system("pause");
return 0;
}
原因分析:不必要的重复搜索。上述做法是遍历i,然后遍历每个v。但v的取值空间是十分有限的(最大值的取值),即使是在不同的i处,相同的v搜索结果完全一致。
修改:直接枚举上述最大值v,其余做法相同。
#include
using namespace std;
typedef long long ll;
const ll mod = 998244353;
int main()
{
int t; cin>>t;
for(int i =0 ;i<t;i++)
{
int n,k;scanf("%d%d",&n,&k);
int a[n];for(int o = 0;o<n;o++)scanf("%d",&a[o]);
if(k > a[n-1] || n == 1)printf("0\n");
else
{
vector<int> m[n];
for(int i = 0;i<n;i++) for(int j = k;j>=1;j--) if(m[i].size()==0||a[i]/j>m[i][m[i].size()-1])m[i].push_back(a[i]/j);
int ans = INT_MAX;
for(int maximal = a[n-1]/k;maximal<=a[n-1];maximal++)
{
int truemaximal = INT_MIN;
int minimum = INT_MAX;
bool f = true;
for(int j = 0;j<n;j++)
{
auto iter = upper_bound(m[j].begin(),m[j].end(),maximal);
iter = prev(iter);
if(iter-m[j].begin()>=0) {truemaximal = max(truemaximal,*iter);minimum=min(minimum,*iter);} else {f=false;break;}
}
if(truemaximal!=maximal) f=false;
if(f) {ans=min(ans,maximal - minimum);}
}
// cout<
// for(int i = 0;i
// {
// for(int v:m[i])
// {
// int maximal = v;
// int minmax = INT_MAX;
// bool f = true;
// for(int j = 0;j
// {
// if(i!=j)
// {
// auto iter = upper_bound(m[j].begin(),m[j].end(),v);
// iter = prev(iter);
// }
// }
// if(f)ans = min(ans,maximal - minmax);
// }
// }
printf("%d\n",ans);
}
}
system("pause");
return 0;
}
总结:注意如何才能避免不必要的重复搜索,可以与以前那道调和级数的题做对比。