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;


}
posted @ 2025-04-16 19:58  LteShuai  阅读(5)  评论(0)    收藏  举报