标签:clu mes 并集 集中 奇数 \n main day 一个
A. 数对子
题目可以转化为,在一些区间的并集中,计算二进制中 1 的数量为奇数的数的个数 s0,以及 1 的数量为偶数的数的个数 s1,答案就是 s0*s1 。因为异或之后 1 的数量为奇数,说明异或前两数奇偶性相异。考虑处理 [0, i] 区间中,1 的数量为奇数的数的个数,写一个 cal1(i) 来计算。
分析发现 (0, 1), (2, 3), (4, 5) ... 这些数对,二进制下的 1 的个数总是相差 1 ,因为个位相差 1. 故 cal1(5) = 3 ,因为 (0, 1), (2, 3), (4, 5) 这三对数里,每一对都可有一个 1 的个数是奇数的数。推理可得:cal1(奇数 n) = (n + 1) / 2 ,cal1(偶数 n) = n / 2 + (pop_count(n) & 1) 。这之后维护一个线段树处理并集就行了。
1 #include <cstdio> 2 #include <algorithm> 3 4 using namespace std; 5 6 typedef long long ll; 7 8 const ll MX = (1ll<<32)-1; 9 const ll _N = 5000000; 10 11 int STCnt = 1, rt = 1, L[_N], R[_N], Lazy[_N]; 12 ll S1[_N], S0[_N]; 13 14 ll cal1(ll n) 15 { 16 if (n&1) return (n+1)/2; 17 return n/2+(__builtin_popcount(n)&1); 18 } 19 20 void MDF(int &p, ll l, ll r, ll s, ll t) 21 { 22 if (!p) p = ++STCnt; 23 if (s <= l && r <= t) { S1[p] = cal1(r)-cal1(l-1), S0[p] = r-l+1-S1[p], Lazy[p] = 1; return; } 24 if (Lazy[p]) return; 25 if (!L[p]) L[p] = ++STCnt; 26 if (!R[p]) R[p] = ++STCnt; 27 ll mid = (l+r)>>1; 28 if (s <= mid && t >= l) MDF(L[p], l, mid, s, t); 29 if (s <= r && t > mid) MDF(R[p], mid+1, r, s, t); 30 S0[p] = S0[L[p]]+S0[R[p]]; 31 S1[p] = S1[L[p]]+S1[R[p]]; 32 return; 33 } 34 35 int main() 36 { 37 int N; 38 scanf("%d", &N); 39 while (N--) { 40 ll l, r; 41 scanf("%lld%lld", &l, &r); 42 MDF(rt, 1, MX, l, r); 43 printf("%lld\n", S1[rt]*S0[rt]); 44 } 45 return 0; 46 }
标签:clu mes 并集 集中 奇数 \n main day 一个
原文地址:https://www.cnblogs.com/ghcred/p/9419315.html