1. 程式人生 > >【bzoj4035】[HAOI2015]陣列遊戲

【bzoj4035】[HAOI2015]陣列遊戲

題目連結

S G 函式niubia
S G ( i )

為第 i 位為白色的估價函式

顯然有

S G ( i ) = m e x { S G ( j
i ) }     ( 2 j n i )

然後有個顯(hen)然(nan)發現的性質
n i = n j 時,有 S G ( i ) = S G ( j )

為什麼有這個結論呢,讓我們來嘗試證明一下
首先當 i 2 n 時,顯然成立,因為 S G ( i ) 都等於 1

i 2 < n 時, n i n j 相同意味著他們的 S G 函式轉移形式也相同,那麼通過簡單數學歸納法就能發現轉移給他們的 S G 值也相同,所以他們的 S G ( i ) 也相同(我也不知道我在說什麼)

反正大概就是這樣了。。。。

然後xjb分塊一下就好了,複雜度是 O ( N ) 的,但是常數小,所以完全過得去

程式碼:

#include<cstdio>
#include<vector>
#include<queue>
#include<ctime>
#include<algorithm>
#include<cstdlib>
#include<stack>
#include<cstring>
#include<cmath>
using namespace std;

typedef long long LL;

const int INF = 2147483647;
const int maxn = 100010;
const int crz = 100007;

struct data{
    int id,val;
};

vector<data> ha[maxn];
int n,m,b,ans,tot;
int sg[maxn],L[maxn],R[maxn],vis[maxn];
int stk[maxn],top;

inline LL getint()
{
    LL ret = 0,f = 1;
    char c = getchar();
    while (c < '0' || c > '9')
    {
        if (c == '-') f = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9') ret = ret * 10 + c - '0',c = getchar();
    return ret * f;
}

inline int find(int x)
{
    int pos = x % crz;
    for (int i = 0; i < ha[pos].size(); i++)
        if (ha[pos][i].id == x)
            return ha[pos][i].val;
}

inline void insert(int id,int val)
{
    int pos = id % crz;
    ha[pos].push_back((data){id,val});
}

inline void init()
{
    for (int i = 1; i <= n; i = n / (n / i) + 1)
        L[++tot] = i , R[tot] = n / (n / i);

    for (int i = tot; i >= 1; i--)
    {
        vis[0] = i;
        int l = L[i],r = R[i],sum = 0;
        for (int j = 2 * l; j <= n; j = (n / (n / j) / l + 1) * l)
        {
            int cnt = n / (n / j) / l - (j - 1) / l;
            vis[sum ^ find(n / j)] = i;
            if (cnt & 1) sum ^= find(n / j);
        }
        for (int j = 0; j <= n; j++) 
            if (vis[j] != i) {sg[i] = j; break;}
        insert(n / l,sg[i]);
    }
}

int main()
{
    #ifdef AMC
        freopen("AMC1.txt","r",stdin);
    #endif
    n = getint();

    init();

    n = getint();
    for (int i = 1; i <= n; i++)
    {
        ans = 0;
        m = getint();
        for (int j = 1; j <= m; j++)
        {
            int pos = getint();
            int id = upper_bound(L + 1,L + tot + 1,pos) - L - 1;
            ans ^= sg[id];
        }
        printf(ans ? "Yes\n" : "No\n");
    }

    return 0;
}

P s . 這種題考場上看到就直接打表好了。。