题面描述
我们定义一个数对 (x,y) 是好的,当且仅当 x≤y,且x xor y 的二进制表示下有奇数个 1
现在给定 nn 个区间 [li,ri][li,ri],你需要对于每个 ∈[1,n],输出有几对好的数 (x,y) 满足 x 和 y 都在 [l1,r1]∪[l2,r2]…∪[li,ri],即两个数都在前 i 个区间的并里
输入格式
第一行一个正整数 n
接下来 nn行每行两个整数 [li,ri],表示第 i 个区间,保证 li≤ri
输出格式
输出 n 行,第 i 行一个整数表示有几对好的数 (x,y)满足 x,y 都在前 i 个区间的并里
样例1
样例输入
3
1 7
3 10
9 20
样例输出
12
25
100
显然我们可以发现xor的奇偶性是有规律的
也就是1的个数的奇偶性是不变的
所以我们只要找到区间并中多少个数的二进制是偶数个1
多少个数的二进制是奇数个1
乘一下就行了
离散化一下
考虑分界点,每个区间就相当于是多少个区间的并
每次暴力覆盖一下就行了
问题就变成了求
中有多少个数有偶数个1
答案就是
和
二进制1的个数奇偶性不同
对于
我们可以数位dp来算,不是很复杂
当然我们也可以贪心
如果M是奇数 奇数偶数分别+(M+1)/2
如果M是偶数 额外处理M的奇偶性即可
线段树维护
我写的是数位dp求,枚举二进制前i为相同,后面按照组合数算一算就好
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ls root * 2
#define rs root * 2 + 1
#define P pair<ll,ll>
ll sum1 , sum2;
bool flag1;
bool flag[1601000];
int n;
int now;
int tr[1601000];
int C[50][50];
struct init{
ll l , r;
}q[101000];
struct node{
int id;
ll num;
}a[1601000];
int hash[1601000] , tot;
ll read()
{
ll sum = 0;char c = getchar();bool flag = true;
while( c < '0' || c > '9' ) {if(c == '-') flag = false;c = getchar();}
while( c >= '0' && c <= '9' ) sum = sum * 10 + c - 48 , c = getchar();
if(flag) return sum;
else return -sum;
}
int need[33];
int change(ll x)
{
int sum = 0;
int k = 33;
while(x)
{
sum += x & 1;
need[--k] = x & 1;
x >>= 1;
}
for(int i = 1;i <= 32 - k + 1;++i)
need[i] = need[i + k - 1];
return 32 - k + 1;
}
P Dp(ll x)
{
if(x == 0) return make_pair(0,1);
ll now1 = 0,now2 = 0;
int sum = change(x);
bool ff = false;
for(int i = 1;i <= sum;++i)
{
if(need[i] == 0) continue;
for(int j = 1;j <= sum-i;j += 2)
if(ff) now2 += C[sum-i][j];
else now1 += C[sum-i][j];
for(int j = 0;j <= sum-i;j += 2)
if(ff) now1 += C[sum-i][j];
else now2 += C[sum-i][j];
ff = !ff;
}
if(ff) now1++;
else now2++;
return make_pair(now1,now2);
}
void solve(int l,int r)
{
if(l > r) swap(l,r);
P ans;
if(q[now].r > r && flag[r+1])ans = Dp(hash[r+1]-1);
else ans = Dp(hash[r]);
sum1 += ans.first;sum2 += ans.second;
if(q[now].l < l && flag[l-1]) ans = Dp(hash[l-1]);
else ans = Dp(hash[l]-1);
sum1 -= ans.first;sum2 -= ans.second;
for(int i = l;i <= r;++i) flag[i] = true;
return;
}
void add(int root,int l,int r,int x,int y)
{
if(l > y || r < x) return;
if(tr[root] == 2) return;
if(l == r)
{
solve(l,l);
tr[root] = 2;
return;
}
if(x <= l && r <= y && tr[root] == 0)
{
solve(l,r);
tr[root] = 2;
return;
}
int mid = (l + r)>>1;
add(ls,l,mid,x,y);add(rs,mid+1,r,x,y);
if(tr[ls] != 0 || tr[rs] != 0) tr[root] = 1;
if(tr[ls] == 2 && tr[rs] == 2) tr[root] = 2;
return;
}
bool mycmp(node a,node b)
{
return a.num < b.num;
}
int tmp[201000];
void init()
{
n = read();
int txt = 0;
for(int i = 1;i <= n;++i)
{
q[i].l = read() ; q[i].r = read();
a[2*i-1].num = q[i].l;a[2*i].num = q[i].r;
txt++;
a[2 * n + txt].num = q[i].l - 1;a[2 * n + txt].id = 2 * n + txt;txt++;
a[2 * n + txt].num = q[i].r + 1;a[2 * n + txt].id = 2 * n + txt;
a[2*i-1].id = 2 * i - 1;a[2*i].id = 2 * i;
}
sort(a + 1,a + 2 * n + txt + 1,mycmp);
for(int i = 1;i <= 2 * n + txt;++i)
if(a[i].num != a[i-1].num) tmp[i] = ++tot , hash[tot] = a[i].num;
else tmp[i] = tot;
for(int i = 1;i <= 2 * n + txt;++i)
if(a[i].id <= 2 * n)
if(a[i].id % 2 == 0)
q[(a[i].id+1)/2].r = tmp[i];
else
q[(a[i].id+1)/2].l = tmp[i];
return;
}
void pre()
{
C[0][0] = 1;
for(int i = 1;i <= 32;++i)
{
C[i][0] = 1;
for(int j = 1;j < i;++j)
C[i][j] = C[i - 1][j] + C[i - 1][j - 1];
C[i][i] = 1;
}
return;
}
int main()
{
pre();
init();
for(now = 1;now <= n;++now)
{
add(1,1,tot,q[now].l,q[now].r);
printf("%lld\n",1ll*sum1 * sum2);
}
return 0;
}