CF1245F: Daniel and Spring Cleaning


CF1245F: Daniel and Spring Cleaning

題意描述:

  • 給定區間\([L,R]\),其中 \((0\leq L,R\leq 10^9)\),問在區間內有多少數對\((x,y)\)滿足\(x+y==x\land y\)

輸入描述:

  • 第一行輸入一個\(T\)表示測試樣例數目。
  • 接下來每一個測試樣例輸入兩個整數\(L,R\)表示區間。

輸出描述:

  • 輸出一個整數表示答案。

思路:

  • 首先對條件進行變形。
  • \(x+y==x\land 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\)的個數。
    • \(0\leq 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)\)數量\((x\in[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;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM