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

题目链接

官网题解写的好清楚,和昨晚Aguin说的一模一样……

这题只和每个数1的个数有关,设每个数1的个数的数组为$b$,就是首先一段如果是好的,要满足两个条件:

1.这一段$b$数组和为偶数,因为奇数总会多出一个1,消不掉。

2.这一段$b$数组中最大的要小于等于这一段总和的一半,因为自己里面的1和自己不能消。

有了这两个条件,先处理第一个条件,做法是枚举左端点,然后统计合法的右端点的个数,就$odd$和$even$数组统计后缀和为奇还是偶,偶-偶,奇-奇就好了,这样能够保证$[l,r]$区间是偶数。

再处理第二个条件,因为每个数$<=10^{18}$,所以最多有60个1,而且每个数不为$0$,所以每个数最少有一个1,那$[l,r]$区间长度大于60后,$b$数组的最大值一定小于等于总和的一半,所以只要把$r$在$[l,l+60]$中,和为偶数最大值大于总和一半的减去就行了。

 

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int maxn = 3e5 + 50;
 5 int b[maxn];
 6 int sum[maxn];
 7 int odd[maxn], even[maxn];
 8 int main()
 9 {
10     int n; scanf("%d", &n);
11     for(int i = 1; i <= n; i++)
12     {
13         ll x;
14         scanf("%lld", &x);
15         while(x)
16         {
17             if(x % 2LL == 1LL) b[i]++;
18             x >>= 1LL;
19         }
20         //printf("%d\n", b[i]);
21     }
22     for(int i = n; i >= 1; i--)
23     {
24         sum[i] = sum[i + 1] + b[i];
25         odd[i] = odd[i + 1], even[i] = even[i + 1];
26         if(sum[i] % 2 == 0) even[i]++;
27         else odd[i]++;
28     }
29     ll ans = 0;
30     for(int i = 0; i <= n; i++) ///枚举左端点
31     {
32         if(sum[i] % 2 == 0) ans += even[i + 1];
33         else ans += odd[i + 1];
34         int mx = 0;
35         if(i == 0) continue; ///i=0,统计的是右端点为n的区间
36         for(int j = i; j <= min(n, i + 65); j++)
37         {
38             mx = max(mx, b[j]);
39             int tmp = sum[i] - sum[j + 1];
40             if((tmp % 2 == 0) && (mx + mx) > tmp) ans--;
41         }
42     }
43     printf("%lld\n", ans);
44     return 0;
45 }

 

 

posted @ 2018-09-24 15:30  汪汪鱼  阅读(398)  评论(2编辑  收藏  举报