【bzoj4035】[HAOI2015]数组游戏

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Joky_2002/article/details/81459469

题目链接

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 . 这种题考场上看到就直接打表好了。。

猜你喜欢

转载自blog.csdn.net/Joky_2002/article/details/81459469