题目网址:http://codeforces.com/problemset/problem/1030/E
题意:
给定一些数,可将区间 l ~r 中某些数的二进制位的1的位置更换, 使得最终区间所有数异或和为0,求这样的区间个数。
思路:
在那里瞎dp了好久,wa的很彻底,借鉴了一下别人的思路。
区间合法的条件是:
这个区间1的个数为偶数,并且区间中二进制位1最多的一个数的二进制个数小于等于和的一半。
我们发现一个数至少可以增加一个二进制位,1e18,大约在2^61次方。那么区间长度大于63时,一定可以把数字相互抵消成0,(即第二个条件一定满足)。所以我们只需统计有多少个偶数区间即可。
对于区间长度小于63的,我们直接暴力枚举即可。
代码如下:
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61#include <iostream> #include <algorithm> #include <cstdio> #include <cstring> #include <string> #include <vector> #include <map> #include <queue> using namespace std; const int maxn = 3e5+100; long long a[maxn]; long long get(long long n) { long long num = 0; while(n>0) { if(n%2!=0) num++; n/=2; } return num; } long long numj[maxn]; long long numo[maxn]; long long all[maxn]; int main() { int n; scanf("%d",&n); for(int i=1; i<=n; i++) scanf("%lld",&a[i]); long long ans = 0; all[0] = 0; numo[0] = 1; for(int i=1; i<=n; i++) { a[i] = get(a[i]); //剪枝操作 all[i] = all[i-1] + a[i]; long long mx = a[i]; for(int j=i-1; j>=max(1,i-62); j--) { mx = max(mx,a[j]); //如果每次求一个get(a[j]) 会TE,所以直接保存就好 long long len = all[i] - all[j-1]; if((len%2==0) && (len>=mx*2)) ans++; } if(i>63) { if(all[i]&1) ans+= numj[i-64]; else ans+= numo[i-64]; } numj[i] = numj[i-1] + (all[i]%2==1); numo[i] = numo[i-1] + (all[i]%2==0); } printf("%lldn",ans); return 0; }
最后
以上就是坚定苗条最近收集整理的关于codeforces 1030E (暴力+思维)的全部内容,更多相关codeforces内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复