zoukankan      html  css  js  c++  java
  • CF1245F: Daniel and Spring Cleaning

    CF1245F: Daniel and Spring Cleaning

    题意描述:

    • 给定区间([L,R]),其中 ((0leq L,Rleq 10^9)),问在区间内有多少数对((x,y))满足(x+y==xland y)

    输入描述:

    • 第一行输入一个(T)表示测试样例数目。
    • 接下来每一个测试样例输入两个整数(L,R)表示区间。

    输出描述:

    • 输出一个整数表示答案。

    思路:

    • 首先对条件进行变形。
    • (x+y==xland y),有(x&y==0),证明略。
    • 那么题目要求的就转化为区间内(x&y==0)的数对数量。
    • 定义(f(l,r))([l,r))区间内满足条件的数对的数量。那么显然有(f(0,r)=2r+f(1,r)),因为(0)可以和任意数字组合。
    • 性质:(f(2l,2r)=3f(l,r))
      • 证明:
      • 考虑满足条件的数对((x,y))的二进制表示。对于最右边的位置,有三种选择方式((0,1),(1,0),(0,0))
      • 选择其他位的方法是(f(l,r)),因此(f(2l,2r)=3f(l,r))
    • 这样我们可以每次对范围除以(2),但这样就要保证我们的(l,r)是偶数,当他不是偶数的时候可以进行如下操作。
    • 定义(g(x,n))为满足以下条件的(y)的个数。
      • (0leq y<n)
      • (x&y==0)
    • 那么当(l)是奇数的时候:
      • (f(l+1,r)=f(l,r)-2(g(l,r)-g(l,l)))
        • 解释:由最上方定义的那个性质可以知道:(f(l,r)=num+f(l+1,r)),其中(num)(l)([l,r])区间内的数满足条件的数对((l,x))数量((xin[l,r]))
        • 那么由(g(i,j))的定义可知,(g(l,r))表示(l)([0,r])范围内满足条件的(y)的个数,(g(l,l))表示在([0,l))范围内满足条件的(y)的个数,那么两个相减就是([l,r))区间内满足条件数对的数量。当然要(*2),因为((x,y))((y,x))为两种情况。
      • 变形为(f(l,r)=f(l+1,r)+2(g(l,r)-g(l,l)))
    • 同样的当(r)为奇数的时候有:
      • (f(l,r-1)=f(l,r)-2(g(r-1,r)-g(r-1,l)))
        • 解释:他的差值也就是(r-1)([l,r))内有多少满足条件的数对。
      • (f(l,r)=f(l,r-1)+2(g(r-1,r)-g(r-1,l)))
    • 于是我们只需要考虑如何快速的计算(g(i,j))
    • 定义(h(x,n))为满足下列条件的(y)的数量。
      • (n-lowbit(n)leq y<n)
      • (x& y==0)
    • 那么有(g(x,n)=h(x,n)+g(x,n-lowbit(n))(n>0))
    • 对于(h(x,n)),我们可以在(logn)的时间内计算出来。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    ll g(int a, int b)
    {
        ll res = 0;
        ll num = 0;
    
        for(int i = 1; i <= b; i <<= 1)
        {
            if(b & i)
            {
                b ^= i;
                if(!(a&b)) res += 1<<num;
            }
            if(!(a&i)) num++;
        }
    
        return res;
    }
    
    ll calc(int a, int b)
    {
        if(a == b) return 0;
        if(a == 0) return 2*b - 1 + calc(1, b);
        ll res = 0;
        if(a & 1)
        {
            //f(l,r)=f(l+1,r)+2(g(l,r)-g(l,l))
            res += 2 * (g(a, b) - g(a,a));
            a++;
        }
        if(b & 1)
        {
            //f(l,r)=f(l,r-1)+2(g(r-1,r)-g(r-1,l))
            res += 2 * (g(b-1, b) - g(b-1, a));
            b--;
        }
        return res + 3 * calc(a/2, b/2);
    }
    
    int main()
    {
        int T; cin >> T;
        int a, b;
        while(T--)
        {
            cin >> a >> b;
            cout << calc(a, b+1) << endl;
        }
        return 0;
    }
    
    
  • 相关阅读:
    【剑指offer】一些简单题05 06
    【剑指offer】11 旋转数组的最小数字
    【剑指offer】10 斐波那契数列
    【剑指offer】 03 数组中重复的数字
    【剑指Offer】 04 二维数组中的查找
    HPCC复习部份
    软工提纲复习
    软件工程复习
    Scala
    [转]对TCP/IP网络协议的深入浅出归纳
  • 原文地址:https://www.cnblogs.com/zxytxdy/p/11780430.html
Copyright © 2011-2022 走看看