Codeforces Round #512 (Div. 2, based on Technocup 2019 Elimination Round 1) E. Vasya and Good Sequences(DP)

题目链接:http://codeforces.com/contest/1058/problem/E

题意:给出 n 个数,对于一个选定的区间,区间内的数可以通过重新排列二进制数的位置得到一个新的数,问有多少个区间满足,区间内的数异或和为 0 。

题解:首先对于一个区间来说,区间内二进制为 1 的个数为奇数时显然不可能满足条件,先统计二进制为 1 的个数为偶数的区间总个数。而在一个区间内,如果某个数二进制下有 x 个 1 ,而区间内其他数的二进制 1 加起来小于 x ,则是不满足的,可以暴力去掉这些不合法的区间。因为一个数 <= 1e18,二进制位为 1 最多只有 59 位。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 #define ull unsigned long long
 5 #define mst(a,b) memset((a),(b),sizeof(a))
 6 #define mp(a,b) make_pair(a,b)
 7 #define pi acos(-1)
 8 #define pii pair<int,int>
 9 #define pb push_back
10 const int INF = 0x3f3f3f3f;
11 const double eps = 1e-6;
12 const int MAXN = 3e5 + 10;
13 const int MAXM = 2e6 + 10;
14 
15 int a[MAXN];
16 ll cnt[2][MAXN];
17 
18 int main() {
19 #ifdef local
20     freopen("data.txt", "r", stdin);
21 //    freopen("data.txt", "w", stdout);
22 #endif
23     int n;
24     scanf("%d",&n);
25     cnt[0][0] = 1;
26     int sum = 0;
27     for(int i = 1; i <= n; i++) {
28         ll b;
29         scanf("%lld",&b);
30         int num = 0;
31         while(b) {
32             if(b & 1) num++;
33             b >>= 1;
34         }
35         a[i] = num;
36         sum += num;
37         cnt[0][i] = cnt[0][i - 1], cnt[1][i] = cnt[1][i - 1];
38         cnt[sum % 2][i]++;
39     }
40     ll ans = 0;
41     for(int i = 1; i <= n; i++) {
42         if(i == 1 || cnt[0][i - 1] - cnt[0][i - 2]) ans += cnt[0][n] - cnt[0][i - 1];
43         else ans += cnt[1][n] - cnt[1][i - 1];
44         int mn = min(n, i + 60), mx = 0;
45         sum = 0;
46         for(int j = i; j <= mn; j++) {
47             sum += a[j];
48             mx = max(mx, a[j]);
49             if(sum % 2 == 0 && sum - mx < mx) ans--;
50         }
51     }
52     printf("%lld
",ans);
53     return 0;
54 }
原文地址:https://www.cnblogs.com/scaulok/p/9696640.html