日常訓練 20170605 EasyProblem

給你 n 個正整數 ai ,回答 m 個詢問:
有三種詢問:
XOR x ,查詢 max(ai xor x)
OR x ,查詢 max(ai or x)
AND x ,查詢 max(ai and x)
n,m100000 ,max(ai)<216
對於 xor 只要高位到低位依次滿足儘量滿足即可,相當與在 Trie 樹上走。對與 andor 有些位是填 01 都一樣,有些位是要儘量填某數的,然後我們就相當於把已經確定的位遮起來,然後枚舉子集,這樣複雜度滿的話是 O(n×log(n)+m×max(ai)) 過不了的,但是今天是 IOI 賽制,我就交了一發,結果比他們寫標算的都快了好幾倍。其實如果對每個數預處理只要 O(n×log(n)+316)

#include<bits/stdc++.h>
const int A = 1 << 16;
template <typename T> void read(T &x) {
    x = 0; char c = getchar();
    for (; !isdigit(c); c = getchar());
    for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
}
int n, q, x, sum[A];
bool exs[A], up[A];
char op[5];
int calc(int l, int r) {
    if (!l) return sum[r];
    return sum[r] - sum[l - 1];
}
int Xor(int x) {
    int l = 0, r = A - 1, ans = 0;
    for (int i=A>>1; l < r; i >>= 1) {
        int mid = (l + r) >> 1;
        if (x & i) {
            if (calc(l, mid))
                r = mid,
                ans += i;
            else
                l = mid + 1;
        }else {
            if (calc(mid + 1, r))
                l = mid + 1,
                ans += i;
            else
                r = mid;
        }
    }
    return ans;
}
int And(int x) {
    for (int i=x; i>=0; i = (i - 1) & x)
        if (up[i]) return i;
}
int Or(int x) {
    int y = (A - 1) ^ x;
    for (int i=y; i>=0; i = (i - 1) & y)
        if (up[i]) return i | x;
}
int main() {
    read(n); read(q);
    while (n--)
        read(x),
        exs[x] = 1,
        sum[x] = 1;
    for (int i=1; i < A; i++)
        sum[i] += sum[i - 1];
    for (int i=0; i < A; i++)
        if (exs[i])
            for (int j=i; j>=0; j = (j - 1) & i) {
                up[j] = 1;
                if (!j) break;
            }
    while (q--) {
        scanf("%s", op);read(x);
        if (op[0] == 'X') printf("%d\n", Xor(x));
        if (op[0] == 'A') printf("%d\n", And(x));
        if (op[0] == 'O') printf("%d\n", Or(x));
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章