2018.8.4 T1(线段树,数位dp,贪心)

题面描述
我们定义一个数对 (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 x o r 1 = 0 , 1 x o r 0 = 1 , 0 x o r 0 = 0 )

所以我们只要找到区间并中多少个数的二进制是偶数个1
多少个数的二进制是奇数个1
乘一下就行了

离散化一下
考虑分界点,每个区间就相当于是多少个区间的并
每次暴力覆盖一下就行了

问题就变成了求 [ l , r ] 中有多少个数有偶数个1
答案就是 a n s r a n s l 1
2 i 2 i + 1 二进制1的个数奇偶性不同
对于 a n s m 我们可以数位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;
}

猜你喜欢

转载自blog.csdn.net/a1035719430/article/details/81414094
t1