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\n",ans); 53 return 0; 54 }