1878E - Iva & Pav

We can, for each bit, calculate the prefix sums of the array ( $ pref[i][j] $ is the number of occurrences of the $ j $ -th bit in the first $ i $ elements of the array. This can be calculated in $ \mathcal{O}(n \log(max(a))) $ . We know that if $ pref[r][j] − pref[l − 1][j] = r − l + 1 $ , then the $ j $ -th bit is present in all elements of the subsegment [ $ l, r $ ] of the array $ a $ , which means the value of $ f(l, r) $ is equal to the sum of all bits for which this condition is true on the subsegment from $ l $ to $ r $ , and we can calculate that in $ \mathcal{O}(\log(max(a))) $ .

Next, for each query, we can use binary search to find $ r $ , by calculating $ f(l, mid) $ . If $ f(l, r) \ge k $ then we found an index for which the condition is true, so we move the left to $ mid + 1 $ , else we move the right to $ mid-1 $ . This solution works in $ \mathcal{O}(Q\cdot\log(N)\cdot\log(max(a))) $ which is around $ 4\cdot10^7 $ operations, with a low constant factor.

It is possible to optimize the solution even more by using sparse tables, to calculate $ f(l, r) $ in $ \mathcal{O}(1) $ therefore removing the $ \log(max(a)) $ factor, but we think that sparse tables are a little bit too advanced of a topic for div3 E, so we didn’t make that solution necessary.

一开始找来找去找不到bug,靠朋友发现是将 s 清零的时候用的memset搞的鬼。。。

注意:

  • 不要用 memset,直接用循环清零
  • 少用全局变量
  • 左移右移时该括起来的括起来
  • 写的时候能压行的尽量压行,代码越少错误越少
// Problem: E. Iva & Pav
// Contest: Codeforces - Codeforces Round 900 (Div. 3)
// URL: https://codeforces.com/contest/1878/problem/E
// Memory Limit: 256 MB
// Time Limit: 5000 ms

#include<iostream>
#include<algorithm>
#include<cstring>	// memset
#define x first
#define y second

using namespace std;

const int N = 200010;

int n, m;
int a[N], s[N][30];
int q, l, k;


bool check(int mid) {
	int value = 0;
	for (int i = 0; i < 30; i ++ ) {
		if ((s[mid][i]-s[l-1][i]) == (mid - l + 1)) {
			value += (1 << i);
		}
	}

	if (value >= k) return true;
	else return false;
}

// 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用:
int bsearch_2(int ll, int r)
{
    while (ll < r)
    {
        int mid = ll + r + 1 >> 1;
        if (check(mid)) ll = mid;
        else r = mid - 1;
    }
    return ll;
}

int main(void) {
	ios::sync_with_stdio(0);
	cin.tie(0);
	int t;
	cin >> t ;
	while (t -- ) {
		cin >> n;
		// O(nlog(max(a)))
		for (int i = 1; i <= n ;i ++ ) {
			cin >> a[i];
			for(int j=0; j<30; j++)
	             s[i][idx] = s[i - 1][idx] + ((a[i] >> j) & 1);
		}
		
		// O(qlog(n)log(max(a)))
		cin >> q;
		while (q -- ) {
			cin >> l >> k;
			if(a[l]<k){
            	cout << -1 << ' ';
            	continue;
        	}
			cout << bsearch_2(l, n) << ' ' ;
		}
		cout << '\n';
		for(int i=1;i<=n;i++)
        	for(int j=0;j<30;j++) 
        		s[i][j]=0;
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值