SIMDの練習問題にと思ったのに、SIMDを書き始める前に通ってしまった。 clangさんは賢すぎるので何も言わずともvector化されてしまってるようだ。 2014年の問題なので当時は違ったのだろう。

problem

最初に列$A$が与えられる。クエリ$[l-1,r)$が与えられるのでそれぞれについて、$m = \max \{ {\bigwedge\mkern-15mu\bigwedge}_{l-1 \le i \lt m} A_i - \bigoplus_{m \le i \lt r} A_i \mid l-1 \lt m \lt r-1 \}$を答えよ。 ただしクエリの先読みはできないものとする。

solution

愚直っぽくやる。$O(NQ)$。

xorについては累積和を取っておいて適当に。 andについては高々$31$回しか変化しないので、bitごとに次の変化する位置のtableを持っておいて飛ぶようにする。

implementation

#include <cstdio>
#include <cstdint>
#include <cstdlib>
#include <algorithm>
#define repeat(i,n) for (int i = 0; (i) < int(n); ++(i))
#define repeat_from(i,m,n) for (int i = (m); (i) < int(n); ++(i))
#define repeat_reverse(i,n) for (int i = (n)-1; (i) >= 0; --(i))
typedef long long ll;
using namespace std;
const ll inf = ll(1e18)+9;
#define N_MAX 100000
int32_t a[N_MAX];
int32_t xor_acc[N_MAX+1];
int and_skip[N_MAX][31];
int main() {
    // input
    int n, q; scanf("%d%d", &n, &q);
    repeat (i,n) scanf("%u", &a[i]);
    // prepare
    xor_acc[0] = 0;
    repeat (i,n) xor_acc[i+1] = xor_acc[i] ^ a[i];
    repeat (k,31) and_skip[n-1][k] = n;
    repeat_reverse (i,n-1) {
        repeat (k,31) {
            and_skip[i][k] = and_skip[i+1][k];
            if (not (a[i+1] & (1<<k))) and_skip[i][k] = i+1;
        }
    }
    // query
    ll m = - inf;
    while (q --) {
        // input
        int l, r; scanf("%d%d", &l, &r);
        if (m == - inf) {
            -- l;
        } else {
            l = (l + abs(m)) % n;
            r = (r + abs(m)) % n + 1;
        }
        // solve
        m = - inf;
        int32_t d = a[l];
        for (int i = l; i < r-1; ) {
            int ni = r-1;
            repeat (k,31) if (d & (1<<k)) ni = min(ni, and_skip[i][k]);
            int32_t x = 0x7fffffff;
            repeat_from (j,i,ni) {
                x = min(x, xor_acc[r] ^ xor_acc[j+1]);
            }
            m = max(m, d -(ll) x);
            d &= a[ni];
            i = ni;
        }
        // output
        printf("%lld\n", m);
    }
    return 0;
}