CodeForces-Look Back
对于这道题 我做了很久 想了很多优化的 但事实上 采用二维数组只会被卡精度卡麻了,时间也耗不起 所以最终还是用了题解的写法 不过确实写的比我好多了
第一个if那 是出现首位比前一个大 可以直接停
在else 里面是指 即使首位的差距弥补了 但是次位 次次位有差距 这种情况 再乘1即可
最后是flag的判断
这是拿来弥补len的问题 首先如果是2 1 这种 由于i的len是大于等于前一个的 然后在补完首位差距之后比不出胜负 但是明显后者不会小于 因为len i 的更大 肯定有贡献的
再就是 len i 太小了 导致即使补完了守位差距 但是 前缀一样 然后i-1有一些次次位的贡献 其实就是跟前面这种情况反着来而已 所以再*2即可
最后就是我觉得最灵魂的一步了
v[i].push_back(k);
就是这一个 太牛了 直接优化了二维 %%%
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
const int range = 1e5 + 5;
int n;
int a[range];
vector<int>v[range];
void solve() {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
v[i].clear();
int k = 29;
for (int j = (1 << 29); j >= 1; j >>= 1, k--) {
if (a[i] >= j) {
a[i] -= j;
v[i].push_back(k);
}
}
}
int ans = 0;
for (int i = 2; i <= n; i++) {
int len = v[i - 1].size();
int len1 = v[i].size();
int c = v[i - 1][0] - v[i][0];
c = max(0LL, c);
for (int j = 0; j < len1; j++) {
v[i][j] += c;
}
bool flag = 0;
//2 1
//11 8
for (int j = 0; j < len && j < len1; j++) {
if (v[i][j] == v[i - 1][j])continue;
if (v[i][j] > v[i - 1][j]) {
ans += c;
flag = 1;
break;
} else {
//1 11
//1000
//1011
//1111
for (int j = 0; j < len1; j++) {
v[i][j]++;
}
flag = 1;
ans += c + 1;
break;
}
}
if (!flag) {
if (len1 >= len) {
// 2 1 可不是+0 这么简单
//但是到了这一步 至少说明+了c 可以达到i>i-1了
//当然也可以一开始就大于 那就是0
ans+=c;
}
else {
//由于len1太小了,len大了 至少后面还有残留的
// 只好再*2 好比 13 12 这种 只好这样
for(int j=0;j<len1;j++)
{
v[i][j]++;
}
ans+=c+1;
}
}
}
cout<<ans<<endl;
return ;
}
signed main() {
ios::sync_with_stdio();
cin.tie(0);
cout.tie(0);
int t ;
cin>>t;
while(t--)
solve();
return 0;
}