區間查詢+位運算 - hdu6085

 

Rikka with Candies

 

 

 

題意:A數組n個數,B數組m個數,q個查詢, 每次給出一個k,詢問有多少對(i,j), 使得Ai % Bj = k, 輸出對數對模2的值

 

數據範圍:

1<=m,n,q<=50,000

1<=Ai,Bi<=50,000

0<=ki<=maxBi

 

分析:

首先,用一個vis數組01方式記錄A數組中的數是否出現過,因爲有Ai % Bj = k,所以也就是(Ai - k) % Bj = 0,不妨設Ai - k = x,那麼Bj則是x的因子,因爲
是Ai % Bj = k,所以k一定比Bj小,即k的取值範圍是[0, Bj)那麼可以枚舉每個x, 再枚舉每個x的因子c,如果c不在B數組出現, 就不管它;否則的話,就在[0, Bj)
中的每一個y的值, 對應的加上vis數組中x + y的值,舉個例子:
vis數組中對於6 7 8 9 10 11的出現情況是0 1 1 0 1 0
對於x枚舉到6,它的因子枚舉到3(假設3在B數組存在)的時候,如果有(Ai - k) % 3 = 0,那麼就是說,如果k可以取值,k在[0, 3)也就是[0, 2]的範圍內,也就轉換爲
Ai = x + k, 也就是6 + [0, 2],那麼現在只需要看對應取值爲k的時候,x + k(Ai)是否存在,如果存在那麼k的值即可加上1, 因爲此時(Ai, 3)形成了一對模爲k的數
設res數組是記錄餘數爲k的對數, x=6,c=3的情況如下所示
vis 6  7  8  9 10 11
    0  1  1  0  1  0
x+k 6 7 8
  res[0, 1, 2] + vis[x + 0, x + 1, x + 2]
= res[0, 1, 2] + vis[6, 7, 8]
= res[0, 1, 2] + [0, 1, 1]
就是說res[0]+0, res[1]+1, res[2]+1, 代表有(6+1)%3=0,(6+2)%3=0,
即(7, 3)形成了一對餘數爲1的數,(8, 3)形成了一對餘數爲2的數
 
還有因爲直接相加複雜度是O(n^2),題目說只需要模2, 那麼可以用異或來寫,用異或的話也不可能一個一個來,所以就用將連續若干個01值壓縮成一個整數來異或,
這樣就是O(n^2 / 32), 還有一點就是對於x=0,因爲所有正整數都是0的因子,對0分開寫,原式就是(0 + k) % Bj = k => k % Bj = k, 就是找在A數組中k存在的前提
下,在B數組中找出比k大的數的數量加進res[k]即可
 

AC代碼

 

#include<bits/stdc++.h>
typedef long long ll;
const int MAXN = 5e4 + 70;
using namespace std;
int a[MAXN], b[MAXN];
int res[MAXN], vis[MAXN];
vector<int> G[MAXN];
ll dig[MAXN][35];
set<int> st;
ll ans[MAXN];

void init() {
    for(int i = 1; i < MAXN - 3; i++) {
        for(int j = 1; j * j <= i; j++) {
            if(i % j) continue;
            G[i].push_back(j);
            if(i / j != j) G[i].push_back(i / j);
        }
        sort(G[i].begin(), G[i].end());
    }
}

int main() {
    init();
    int n, m, q, k, T;
    scanf("%d", &T);
    while(T--) {
        st.clear();
        memset(vis, 0, sizeof vis);
        memset(res, 0, sizeof res);
        memset(ans, 0, sizeof ans);
        scanf("%d%d%d", &n, &m, &q);
        int max_data = -1;
        for(int i = 0; i < n; i++) {
            scanf("%d", &a[i]);
            vis[a[i]] = 1;
            max_data = max(max_data, a[i]);
        }
        for(int i = 0; i < m; i++) {
            scanf("%d", &b[i]);
            st.insert(b[i]);
        }
        sort(b, b + m);
        for(int i = 1; i <= 5e4; i++) {
            ll su = 0;
            for(int j = 0; j < 32; j++) {
                su = su * 2 + vis[i + j];
                dig[i][j + 1] = su;
                dig[i][j + 1] <<= (31 - j);
            }
        }

        for(int i = 1; i <= max_data; i++) {
            for(int j = 0; j < G[i].size(); j++) {
                int x = G[i][j];
                if(!st.count(x)) continue;
                int L = 0, R = x - 1;
                while(L <= R) {
                    int d = L / 32;
                    if(i + L > 5e4) break;
                    if(R - L >= 31) {
                        ans[d] ^= dig[i + L][32];
                        L += 32;
                    } else {
                        ans[d] ^= dig[i + L][R - L + 1];
                        L = R + 1;
                    }
                }
            }
        }

        int num = 0;
        for(int i = 0; i * 32 <= 5e4; i++) {
            int j = (i + 1) * 32 - 1;
            int t = 32;
            while(t--) { res[j] = ans[i] & 1; j--; ans[i] >>= 1; }
        }
        for(int i = 0; i < n; i++) {
            int x = a[i];
            res[x] += m - (upper_bound(b, b + m, x) - b);
        }
        while(q--) {
            scanf("%d", &k);
            printf("%d\n", res[k] & 1);
        }
    }
    return 0;
}


轉自:

 

 

 

hnust_Derker

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章