1. 程式人生 > >luoguP3235 [HNOI2014]江南樂 數論分塊 + 博弈論

luoguP3235 [HNOI2014]江南樂 數論分塊 + 博弈論


感覺其實很水?

題目就是一個Multi SG遊戲,只需要預處理出所有的\(sg\)值即可\(O(Tn)\)計算

對於計算\(sg[n]\)而言,顯然我們可以列舉劃分了\(x\)堆來檢視後繼狀態

那麼,有\(n\;mod\;x\)\(\left \lfloor \frac{n}{x} \right \rfloor + 1\)的堆以及\(x - n\;mod\;x\)\(\left \lfloor \frac{n}{x} \right \rfloor\)的堆

暴力轉移就是\(O(10^{10})\)

顯然上面可以數論分塊,再討論一下奇偶即可

複雜度\(O(10^5 \sqrt 10^5)\)


#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

#define ri register int
#define rep(io, st, ed) for(ri io = st; io <= ed; io ++)
#define drep(io, ed, st) for(ri io = ed; io >= st; io --)

const int sid = 2e5 + 5;
    
int T, F, tim;
int sg[sid], mex[sid];
    
inline void init() {
    rep(i, F, 100000) {
        ++ tim;
        for(ri ii = 2, jj; ii <= i; ii = jj + 1) {
            jj = i / (i / ii); 
            int p = i / ii, S = i - p * ii, S2 = ii - S, SG = 0;
            if(S & 1) SG ^= sg[p + 1];
            if(S2 & 1) SG ^= sg[p]; mex[SG] = tim;
            if(ii + 1 > jj) continue;
            S = i - p * (ii + 1); S2 = (ii + 1) - S; SG = 0;
            if(S & 1) SG ^= sg[p + 1];
            if(S2 & 1) SG ^= sg[p]; mex[SG] = tim;
        }
        rep(j, 0, 100000) if(mex[j] != tim) 
        { sg[i] = j; break; }
    }
}
    
int main() {
    cin >> T >> F;
    init();
    while(T --) {
        int n, x, SG = 0;
        cin >> n;
        rep(i, 1, n) { cin >> x; SG ^= sg[x]; }
        printf("%d ", SG ? 1 : 0);
    }
    return 0;
}