zoukankan      html  css  js  c++  java
  • 246.数对子

    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<bits/stdc++.h>
     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
    ",num[1][0]*num[1][1]);
    49     }
    50 }
    51 int main(){
    52     init();    
    53     
    54     return 0;
    55 }
  • 相关阅读:
    VC 常见问题百问
    python windows 环境变量
    Check server headers and verify HTTP Status Codes
    Where are the AES 256bit cipher suites? Please someone help
    outlook 如何预订会议和会议室
    安装Axis2的eclipse插件后,未出现界面
    windows 环境变量
    python 时间日期处理汇集
    openldap学习笔记(使用openldap2.3.32)
    set p4 environment in windows
  • 原文地址:https://www.cnblogs.com/degage/p/9685123.html
Copyright © 2011-2022 走看看