这里采用了一个技巧,可以有效地避免了超时,记录一下前一个数乘2的数量,这是什么用处呢?举个例子:
7 1 5这个数组,首先1乘以3个二会大于7,记录pre=3,因为1* 2=2,2* 2=4,而4小于5,这意味着从5乘到大于等于8只需要1个2,因为1到五之间已经乘了两个2了,这就避免了许多不必要的运算。
就比如,当要改变的数组元素位置已经非常靠后面的情况下,显然它前一个数已经变得非常大,当前位置的元素又很不巧的是1,那么就需要很多次循环直到它再次大于前一个数为止,这样时间复杂度过高了,相比之下,直接在前一个数的乘2次数上修改时间复杂度大大下降
#include<bits/stdc++.h>
using namespace std;
const int M=1e5+5;
typedef long long ll;
ll a[M];
int main(){
int t; cin>>t;
while(t--){
memset(a,0,sizeof(a));
int n; cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
ll cnt=0; ll preb=0;
for(int i=2;i<=n;i++){
ll tmp=a[i];
if(tmp<a[i-1]){
while(tmp<a[i-1]){
tmp*=2;
preb++;
}
}
else{
while(tmp>=a[i-1]*2&&preb){
tmp/=2;
preb--;
}
}
cnt+=preb;
}
cout<<cnt<<endl;
}
return 0;
}