见证者为见证而来,铭记者因铭记而生|

园龄:粉丝:关注:

[CF2053C] Bewitching Stargazer 题解

我们不妨直接递归模拟算答案。
定义 f(l,r) 表示左右端点为 l,r 的答案。记 midl+r2,于是:

f(l,r)={f(l,mid)+f(mid+1,r)(rl+1)0(mod2)f(l,mid1)+f(mid+1,r)+midotherwise.

这样做显然会 T,考虑如何优化。我们注意到每次由 mid 分割,左右两边是对称的。显然,mid 右边所有取到的点都可以由左边平移得到。设区间长度是 len,这个平移量 d 就是 len2。设左(右)边取到了 c 个点,故右边的答案就是左边的答案加上 dc

于是改写一下函数,将求解函数定义为 pair 型,first 存答案,second 存区间内能取到的个数,直接算就好了。

#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define Linf 0x3f3f3f3f3f3f3f3f
#define pii pair<int, int> 
#define all(v) v.begin(), v.end()
#define int long long
using namespace std;

//#define filename "xxx" 
#define FileOperations() freopen(filename".in", "r", stdin), freopen(filename".out", "w", stdout)


namespace Traveller {
	
	int n, k;
	pii operator + (pii a, pii b) { return pii(a.first + b.first, a.second + b.second); }
	pii solve(int n) {
		if(n < k) return pii(0, 0);
		pii res = solve(n/2);
		if(n & 1) return res + res + pii(res.second * (1+n >> 1) + (1+n >> 1), 1);
		return res + res + pii(res.second * (n >> 1), 0);
	}
	
	void main() {
		scanf("%lld%lld", &n, &k);
		printf("%lld\n", solve(n).first);
	}
}

signed main() {
	#ifdef filename
		FileOperations();
	#endif
	
	int _;
	cin >> _;
	while(_--) Traveller::main();
	return 0;
}


posted @   wfc284  阅读(42)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起