博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
246.数对子
阅读量:5138 次
发布时间:2019-06-13

本文共 2659 字,大约阅读时间需要 8 分钟。

Description

我们定义一个数对 (x,y) 是好的,当且仅当 xy,且 x xor y的二进制表示下有奇数个 1

现在给定 nn 个区间 [li,ri],你需要对于每个 i[1,n],输出有几对好的数 (x,y)满足 x 和 y 都在 [l1,r1][l2,r2]...[li,ri],即两个数都在前 i 个区间的并里

Input

第一行一个正整数 n

接下来 n 行每行两个整数 [li,ri],表示第 i个区间,保证 liri

Output

输出 n 行,第 i行一个整数表示有几对好的数 (x,y) 满足 x,y 都在前 i 个区间的并里

Sample Input

3

1 7

3 10

9 20

Sample Output

12

25

100

Hint

对于 30%30% 的数据,有 1n1001≤n≤100,1liri1001≤li≤ri≤100

对于 50%50% 的数据,有 1n10001≤n≤1000,1liri23211≤li≤ri≤232−1

对于 100%100% 的数据,有 1n1051≤n≤105, 1liri23211≤li≤ri≤232−1

时间限制:2s

空间限制:512MB

Solution

先补充几个小知识点(快速求出一个数的二进制中有多少个1):

x=x&(x-1)(递归求法,适用于单个数)

 
表达式的意思就是:把x的二进制表示 从低位开始,将遇到的第一个为1的 二进制位 置0。

int calc=0;while(x) x=x&(x-1),calc++;calc即为所求值

 求0到x中有多少二进制含1个数为奇数的:

long long calc(long long x){    long long tmp=x,tot=0;    while(tmp)    {        if(tmp&1)tot++;        tmp>>=1;    }    return (x>>1)+((x&1) || (tot&1));} 证明:00 01 10 11 100 101 110 111....继续下去可以发现规律是偶奇奇偶奇偶偶奇.... 所以x>>1之前一半的,如果x为奇数(会少算一个)或其本身有奇数个1得加上

p.s.当线段树叶子节点有n个时,应开总共2^(log2n+1)个点,即2*n个点

 正经题解开始:

首先,对于每个数对(x,y), 若要x xor y的二进制表示下有奇数个 1,则必定一者含奇数个1,一者含偶数个。

证明:若两个都为奇数,1.则奇减奇等于偶(重叠个数为奇个)2.奇减偶先为奇(重叠个数为偶数个),奇加奇等于偶

           若两个都为偶数,则可同上证明

           一奇一偶,1.奇减奇等于偶,偶减奇等于奇,奇加偶等于奇2.奇减偶等于奇,偶减偶等于偶,偶加奇等于奇

所以我们采取线段树来维护区间含奇数个1和含偶数个1的个数,对于区间l,r,则用上述中所介绍的calc函数,来calc(r)-calc(l-1)得到奇数个1个数以及r-l+1-(calc(r)-calc(l-1))得到偶数个1个数

每次输入一个区间加进去统计一个区间,然后输出总的相乘即可。p.s.线段树很好的解决了区间相交的问题,在以及统计过的区间标记vis[now]=1;

上代码:

1 #include
2 #define maxn 100005 3 using namespace std; 4 typedef long long ll; 5 ll num[maxn<<4][2]; 6 int lc[maxn<<4],rc[maxn<<4],rt=0,np=0; 7 int n; 8 bool vis[maxn<<4]; 9 void upload(int now){10 num[now][0]=num[lc[now]][0]+num[rc[now]][0];11 num[now][1]=num[lc[now]][1]+num[rc[now]][1];12 }13 ll calc(ll x)14 {15 ll t=x,tot=0;16 while(t)17 {18 if(t&1)tot++;19 t>>=1;20 }21 return (x>>1)+((x&1) || (tot&1));22 }23 void update(int &now,ll l,ll r,ll x,ll y){24 if(!now) now=++np;25 if(vis[now]) return;26 if(l>=x&&r<=y){27 num[now][1]=calc(r)-calc(l-1);28 num[now][0]=r-l+1-num[now][1];29 vis[now]=1;30 return;31 }32 ll m=(l+r)>>1;33 if(y<=m)update(lc[now],l,m,x,y);34 else if(x>m)update(rc[now],m+1,r,x,y);35 else{36 update(lc[now],l,m,x,y);37 update(rc[now],m+1,r,x,y);38 }39 40 upload(now);41 }42 void init(){43 scanf("%d",&n);44 ll L,R,mx=1ll<<32;45 for(int i=1;i<=n;i++){46 scanf("%lld%lld",&L,&R);47 update(rt,1,mx,L,R);48 printf("%lld\n",num[1][0]*num[1][1]);49 }50 }51 int main(){52 init(); 53 54 return 0;55 }

转载于:https://www.cnblogs.com/degage/p/9685123.html

你可能感兴趣的文章
OpenFire 的安装和配置
查看>>
web.config详解
查看>>
ZJOI2018游记Round1
查看>>
侧边栏广告和回到顶部
查看>>
spring父子容器
查看>>
windows+两个ubuntu系统的引导启动问题
查看>>
修改默认共享内存tmpfs大小
查看>>
ABAP版连连看
查看>>
UI基础六:UI报弹窗确认
查看>>
SAP跳过权限检查/前提是有debug权限
查看>>
13年学习
查看>>
HTML5+ API 学习
查看>>
CodeForces 670D2 Magic Powder 二分
查看>>
不能以方法的方式使用不可调用的“system.web.httprequest.querystring”
查看>>
试用dotnetbar10,提供下载链接
查看>>
iptables动作总结之一
查看>>
Integer to Roman——相当于查表法
查看>>
关于ldap的学习
查看>>
JDBC获取表的主键
查看>>
[转]SpringMVC Controller介绍及常用注解
查看>>