三十年河东,三十年河西|

自动机

园龄:1年10个月粉丝:2关注:4

Codeforces Round 900 (Div. 3)

E

题意:

给你一个数组a, 定义f(l, r) = a[l] & a[l + 1]...&a[r],现在给你q次询问,每次给你一个l,k,求一个最大的r使得f(l, r) >= k

思路:

先拆位计算,就把原数组看成一个二进制的二维数组n行30列,这样的话可以发现对于一个区间[l, r]来说,只有当某一列在这段区间内全为一才能有贡献
所以要先求一下每一列的前缀和,这样就可以O(1)判断某一段是不是全一,那样每次查询我们就二分找到最后一个符合条件的(如果x符合,那么小于x的肯定也符合因为都是一)

inline void solve() 
{
	int n; cin >> n;
	std::vector<int> a(n + 1);

	for (int i = 1; i <= n; i++) 
		cin >> a[i];

	vector<array<int, 30>> s(n + 1);
	for (int i = 1; i <= n; i++)
		for (int j = 0; j < 30; j++)
		{
			s[i][j] = s[i - 1][j];
			if (a[i] >> j & 1) s[i][j]++;
		}

	int q; cin >> q;
	while (q--)
	{
		int t, k; cin >> t >> k;
		int l = t, r = n;

		auto check = [&](int l, int r)
		{
			LL ans = 0;
			for (int i = 0; i < 30; i++)
				if (s[r][i] - s[l - 1][i] == r - l + 1) ans += 1 << i;

			return ans >= k; 
		};

		while (l < r)
		{
			int mid = (l + r + 1) / 2;
			if (check(t, mid)) l = mid;
			else r = mid - 1;
		}

		if (check(t, l)) cout << l << ' ';
		else cout << -1 << ' ';
	}
	cout << endl;
}

本文作者:自动机

本文链接:https://www.cnblogs.com/monituihuo/articles/17735373.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

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