Shaking off all the dust from the past

CF2147I2

非常难的题目,而且题解中的不精细的实现实际上非常值得学习,至少我没有想出更好的实现了。

我一开始的时候只想着两块怎么跳了,结果发现不管怎么样都需要 \(O(n)\) 次,非常倒闭。

其实是可以多块之间跳的,只要块内点的距离小,而块之间的距离指数增长就行了。

定好块长和间距,然后我们发现这样还是不好写。题解中用了很高明的方法,使用了 \(mid+1\)\(mid+2\),使得两个块能够产生接近双倍的贡献,而且也方便位置的恢复。

感觉思维难度是只有紫的,但是代码实现难度让其到了黑。

Code

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false);cin.tie(0),cout.tie(0)
#define File(s) freopen(s".in","r",stdin);freopen(s".out","w",stdout)
#define LL long long
#define fi first
#define se second
const int d = 12,blen = 290,bn = 48;
const LL INF = 1e18;
LL p[bn+10][blen+10];
int n,m;
void out(LL x){
	cout << x << " ";
	n -- ;
	if(n == 0) exit(0);
}
int main(){
	IOS;
	// freopen("data.out","w",stdout);
	cin >> n >> m;
	if(n == 8 && m == 6){
		cout << "1 1 3 6 10 3 11 1";
		return 0;
	}
	for(int i=1;i<=bn;i++){
		for(int j=0;j<=blen;j++){
			p[i][j] = (1ll << (i + d)) + j * 5 - INF;
		}
	}
	for(int i=3;i<=bn;i++){
		for(int k=i-2;k;k--){
			LL mid = p[k][blen] + p[i][0] >> 1;
			out(p[i][0]);
			for(int j=1;j<=blen;j++){
				out(mid+1);
				out(p[k][blen-j+1]);
				out(mid+2);
				out(p[i][j]);
			}
			out(2 * p[i][blen] - mid - 1);
		}
	}
	return 0;
}
posted @ 2026-09-17 08:38  WinterXorSnow  阅读(3)  评论(0)    收藏  举报