题目大意
给出一个长度为 n ( n < = 100000 ) n(n<=100000) n(n<=100000)的数组,在第 i i i秒时可以任意选出一些数使它们的值增加 2 i − 1 2^{i-1} 2i−1,问如果要使得该数组不递减至少需要多少秒?
分析过程
(感觉这道题挺妙的…… )我们经过分析可以发现,如果从左到右遍历数组,对于数组中碰到的第一组满足
a
[
i
]
>
a
[
i
+
1
]
a[i]>a[i+1]
a[i]>a[i+1]的两个相邻元素,我们必然要增加
a
[
i
+
1
]
a[i+1]
a[i+1]来消除这个逆序,我们的最优贪心策略必然是使得
a
[
i
+
1
]
a[i+1]
a[i+1]增加到与
a
[
i
]
a[i]
a[i]相等,这样可以保证用的时间是最少的。这个时候,如果对于二进制位运算比较敏感的话,很容易察觉到,所用的时间就是
h
i
g
h
_
b
i
t
(
x
)
high\_ bit(x)
high_bit(x),其中,
x
=
a
[
i
]
−
a
[
i
+
1
]
x=a[i]-a[i+1]
x=a[i]−a[i+1],
h
i
g
h
_
b
i
t
(
x
)
high\_ bit(x)
high_bit(x)表示
x
x
x对应的二进制位的最高位置(一个策略对应于一个二进制表示,以二进制位置表示时间,1或0表示是否叠加对应值。)。
现在,我们一般化这个思路,在使得
a
[
i
+
1
]
=
=
a
[
i
]
a[i+1]==a[i]
a[i+1]==a[i]之后,如果后面的值大于等于这个值那就自然满足不递减,这个时候我们就更新一下最大值(因为后面的值应该比左侧过来的最大值大),如果小于的话,我们更新一下答案,即
a
n
s
=
m
a
x
(
a
n
s
,
h
i
g
h
_
b
i
t
(
m
a
x
i
−
a
[
i
]
)
)
ans=max(ans, high\_ bit(maxi-a[i]))
ans=max(ans,high_bit(maxi−a[i]))
AC代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 100;
typedef long long ll;
ll n, a[maxn], c[maxn];
ll high_bit(ll x){
ll i = 63, e = 1;
while(!(x & (e << i))) --i;
return i + 1;
}
void solve(){
ll i, x, maxi = -10000000000, ans = 0;
for(i=1;i<=n;++i){
if(a[i] >= maxi) maxi = a[i];
else{
ll temp = high_bit(maxi - a[i]);
ans = max(ans, temp);
}
}
cout<<ans<<'\n';
}
int main(){
int t, i, j;
ios::sync_with_stdio(false);
cin>>t;
while(t--){
cin>>n;
for(i=1;i<=n;++i) cin>>a[i];
solve();
}
return 0;
}