codeforces 1438 E. Yurii Can Do Everything (暴力)

题目链接:https://codeforces.com/contest/1438/problem/E

根据题目性质,答案不会太大

枚举左端点 \(l\), 令 \(k\)\(a_l\) 的最高位,那么可能合法的右端点 \(r\) 一定在区间和小于 \(2^{k + 1}\) 的区间内,暴力寻找右端点 \(r\) 即可
正着做完以后再反着来一遍,去重即可

而每个右端点不会被扫描超过 \(lg(a_r)\) 次,因为对于每一位来说,如果这一位已经被扫到过了,那么如果又被扫到,区间和必定大于等于 \(2^{k+1}\)

于是时间复杂度位 \(O(n*log(a_i))\)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll, ll> P;

const int maxn = 200010;

int n;
ll a[maxn], sum[maxn];

map<P, bool> mp;

ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }

int main(){
	n = read();
	for(int i = 1 ; i <= n ; ++i) a[i] = read(), sum[i] = sum[i - 1] + a[i];
	
	int ans = 0;
	for(int i = 1 ; i <= n - 2 ; ++i){ // 枚举 l 
		int k;
		for(int j = 30 ; j >= 0 ; --j){ // 找到最高位 1 
			if((a[i] >> j) & 1){
				k = j;
				break;
			}
		}
		
		for(int j = i + 2 ; j <= n ; ++j){
			if(sum[j - 1] - sum[i] >= (1 << (k + 1))) break;
			if(sum[j - 1] - sum[i] == (a[i] ^ a[j])) {
//				printf("%d %d %lld %lld\n", i, j, sum[j - 1] - sum[i], a[i] ^ a[j]); 
				++ans;
				mp[make_pair(i, j)] = true;
			}
		}
	}
//	printf("\n", ans);

//	for(int i = 1 ; i <= n ; ++i){
//		for(int j = i + 2 ; j <= n ; ++j){
//			if(mp.find(make_pair(i, j)) != mp.end()){
//				printf("%d %d\n", i, j);
//			}
//		}
//	} 

	// 倒着做 
	for(int i = n ; i >= 3 ; --i){ // 枚举 l 
		int k;
		for(int j = 30 ; j >= 0 ; --j){ // 找到最高位 1 
			if((a[i] >> j) & 1){
				k = j;
				break;
			}
		}
		
		for(int j = i - 2 ; j >= 1 ; --j){
			if(sum[i - 1] - sum[j] >= (1 << (k + 1))) break;
			if(sum[i - 1] - sum[j] == (a[i] ^ a[j]) && (mp.find(make_pair(j, i)) == mp.end())) { //
//				printf("%d %d %lld %lld\n", j, i, sum[i - 1] - sum[j], a[i] ^ a[j]); 
				++ans;
			}
		}
	}
	
	printf("%d\n", ans);
	
	return 0;
}
posted @ 2021-01-10 23:16  Tartarus_li  阅读(70)  评论(0编辑  收藏  举报