【bzoj4035】[HAOI2015]数组游戏

题目链接

SG S G 函数niubia
SG(i) S G ( i ) 为第 i i 位为白色的估价函数

显然有
SG(i)=mex{SG(ji)}  (2jni)

然后有个显(hen)然(nan)发现的性质
ni=nj ⌊ n i ⌋ = ⌊ n j ⌋ 时,有 SG(i)=SG(j) S G ( i ) = S G ( j )

为什么有这个结论呢,让我们来尝试证明一下
首先当 i2n i ∗ 2 ≥ n 时,显然成立,因为 SG(i) S G ( i ) 都等于 1 1

i2<n时, ni ⌊ n i ⌋ nj ⌊ n j ⌋ 相同意味着他们的 SG S G 函数转移形式也相同,那么通过简单数学归纳法就能发现转移给他们的 SG S G 值也相同,所以他们的 SG(i) S G ( i ) 也相同(我也不知道我在说什么)

反正大概就是这样了。。。。

然后xjb分块一下就好了,复杂度是 O(N) 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;
}

Ps. P s . 这种题考场上看到就直接打表好了。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值