山東理工大學網絡擂臺賽——G.蒟蒻們最後的掙扎(前綴和+異或思想)

山東理工大學網絡擂臺賽——G.蒟蒻們最後的掙扎(前綴和+異或思想)

題目描述

Description
在 LJJ 的「壓迫」下,每一個蒟蒻要出三道題,正所謂哪裏有剝削哪裏就有反抗,蒟蒻們給強大的 LJJ 出了一道題,若是 LJJ 解出了題,蒟蒻們才心甘情願給 LJJ 當苦力。問題其實很簡單:給你一個區間 L 到 R,要求你求出從 L 異或到 R 的值。可是LJJ還(不)有(屑)很(作)多(這)事(種)要(水)忙(題),因而他找到了你但願你能寫個程序幫他解決這道題。html

Input
第一行一個T(1 ≤ L ≤ T ≤ 1e5),表示有 T 組輸入。算法

如下 T 行,每行包含兩個整數 L 和 R(1 ≤ L ≤ R ≤ 1e5)用空格分開,表示要求異或和的區間。數組

Output
對於每組輸入,輸出一個整數表示 L 到 R 全部數字的異或和markdown

Sample Input
2
1 2
3 6
Sample Output
3
4
Hint
異或(xor)是一個數學運算符。它應用於邏輯運算。異或的數學符號爲「⊕」,計算機符號爲「xor」。網絡

0 ⊕ 0 = 0,1 ⊕ 0 = 1, 0 ⊕ 1 = 1, 1 ⊕ 1 = 0。ide

性質:a ⊕ a = 0, a ⊕ 0 = aatom

C語言中能夠用「^」進行異或運算。spa

樣例1: 1 ⊕ 2 = 3,樣例 2:3 ⊕ 4 ⊕ 5 ⊕ 6 = 4設計

個人AC程序

#include <cstdio>

const int maxn = 1e5 + 10;
int xorSum[maxn], t, l, r;

int main()
{
    xorSum[1] = 1;
    for(int i = 2;i < maxn;++i)
    {
        xorSum[i] = i ^ xorSum[i - 1];
    }
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d %d", &l, &r);
        printf("%d\n", xorSum[r] ^ xorSum[l - 1]);
    }
    return 0;
}

算法分析與設計

這題暴力算法確定是 O ( n t ) O(nt) O(nt),確定是沒法經過的!code

這種區間和查詢的問題,最簡單的思路就是前綴和、差分,其次就是線段樹之類的。先看看前綴和,這裏的前綴和顯然和通常的前綴和不同,普通的前綴和是設定數組 S u m [ i ] = a [ i ] + S u m [ i − 1 ] Sum[i] = a[i] + Sum[i-1] Sum[i]=a[i]+Sum[i1],用加法來描述一種「和」,而這裏不是求和,而是求區間的異或。那麼異或和求和有什麼共同點呢

求和是前綴的累積再加上當前值,而異或也是前綴的異或累計再異或當前值,這本質上是同樣的!

那麼有什麼區別呢?

在對前綴和進行差分的時候,是直接相減,那是由於:
S u m ( l , r ) = a [ l ] + … + a [ r ] = S u m [ r ] − S u m [ l − 1 ] Sum(l, r) = a[l]+…+a[r]=Sum[r]-Sum[l-1] Sum(l,r)=a[l]++a[r]=Sum[r]Sum[l1]

而對前綴異或進行差分的時候,是怎樣的呢?先推導一下:
x o r S u m ( l , r ) = ( a [ 1 ] ⊕ … ⊕ a [ r ] ) ⊕ ( a [ 1 ] ⊕ … a [ l − 1 ] ) xorSum(l, r)=(a[1]⊕…⊕a[r])⊕(a[1]⊕…a[l-1]) xorSum(l,r)=(a[1]a[r])(a[1]a[l1])
這是由於: ( a ⊕ b ) ⊕ b = a (a⊕b)⊕b=a (ab)b=a,因此差分能夠歸結爲:
x o r S u m ( l , r ) = x o r S u m [ r ] ⊕ x o r S u m [ l − 1 ] xorSum(l, r)=xorSum[r]⊕xorSum[l-1] xorSum(l,r)=xorSum[r]xorSum[l1]
綜上所述,程序就很好編寫了!

結束語

有想要探討、合做的小夥伴能夠關注我,有問題能夠發郵件給我,個人郵箱是:2329313458@qq.com

相關文章
相關標籤/搜索