只听课不思考不记笔记==假把式
这道题目乍一看上去很难,但如果细细分析就会发现这道题目其实不是特别难,主要是用到了数学的不等式很多人想不到
1.题目拆解
题目里面有一个特别难用的一个点,就是它说的ti的点,但是细细想想就会明白其中的奥秘。
那这句话转意过来就是,对于第i个芦笋最终前面有i个芦笋,那再进一步想就是最终第i个芦笋排在第i+1个位置。
那么其实我们就可以根据这个数组对我们的第一个的数组进行重新排列,我们可以把重新排列后的数组叫做rk,同时我们也要对我们的ak进行二次排列,我们可以叫它ak,那么我们就可以列出不等式。
2.解题思路
那么其实题目叫我们求的就是我们的x最小应该取多少,那么这个时候我们可以随便拿出一个式子进行化简
然后我们再分情况进行讨论
接着我们再巧用数学里面的一个转化式子
这个可以大家自己举个例子试试都是成立的,大家以后可以把这个式子记住,遇到的时候用就行
那么我们这道题目最终求的就是在这个区间里面,x所能取的最小值。
3.优化
对于上面我们要二次排列的方式,显然是非常麻烦的,我们可以用一个数组去存每个每个位置最终的对应原位置,这样我们的代码就简单很多了。
同时我们如果直接列不等式显然代码太长可读性也比较差,我们可以这样。
这样就可以让我们的代码更好维护
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
const int N=200010;
int h[N],a[N],rk[N];
int main()
{
int cnt,n;
cin>>cnt;
while(cnt--)
{
cin>>n;
for(int i=0;i<n;i++)cin>>h[i];
for(int i=0;i<n;i++)cin>>a[i];
for(int i=0;i<n;i++){
int tmp;
cin>>tmp;
rk[tmp]=i;
}
int l=0,r=1e9;
for(int i=0;i<n-1;i++)//遍历每个不等式
{
int A=h[rk[i+1]]-h[rk[i]];
int B=a[rk[i]]-a[rk[i+1]];
if(B>0)
l=max((int)floor((double)A/B)+1,l);//x>=
else if(B<0)
r=min((int)ceil((double)A/B)-1,r);//x<=
else if(A>=0)
{
r=-1;
break;
}
}
if(l>r)l=-1;
cout<<l<<endl;
}
return 0;
}