zoukankan      html  css  js  c++  java
  • [CQOI2013]新Nim游戏

    貌似一道经典题

    在第一个回合中,第一个游戏者可以直接拿走若干个整堆的火柴。可以一堆都不拿,但不可以全部拿走。第二回合也一样,第二个游戏者也有这样一次机会。从第三个回合(又轮到第一个游戏者)开始,规则和Nim游戏一样
    

    几堆石子,先手拿若干堆(可以不拿,不能拿光),然后后手一样操作一次,然后是正常的nim

    首先无解的情况只有一种,(k)(0)的时候(题目里说了,整数(k))

    考虑后拿的时候,剩下集合的真子集不能有异或和等于自己的,那么干脆直接先手拿到这个状态。

    考虑计算能够异或出来的数,可以使用线性基

    显然可以证明剩下的堆数不能大于32,对于消元消出的每一个基,求出它最大的可能值,作为剩下的

    可以证明这样拿是最优的(我没想过怎么证明)

    没开long long爆了几发

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    
    const int MAXN = 110;
    typedef long long LL;
    LL nu[MAXN], n, bak, vt[MAXN], va[MAXN];
    bool cnt[MAXN];
    
    int main() {
    	scanf("%lld", &n); if (!n) return puts("-1"), 0;
    	LL ans = 0;
    	for (int i = 1; i <= n; ++i) {
    		scanf("%lld", nu + i);
    		ans += vt[i] = nu[i];
    	}
    	for (int dig = 31; ~dig; --dig) {
    		int at = 0;
    		for (int i = 1; i <= n; ++i) {
    			if (!cnt[i] && nu[i] >> dig & 1) {
    				if (vt[i] > va[dig]) {
    					at = i;
    					va[dig] = vt[i];
    				}
    			}
    		}
    		if (!at) continue;
    		cnt[at] = true;
    		for (int i = 1; i <= n; ++i) if (i != at)
    			if (nu[i] >> dig & 1)
    				nu[i] ^= nu[at];
    	}
    	for (int i = 0; i <= 31; ++i) ans -= va[i];
    	printf("%lld
    ", ans);
    	return 0;
    }
    
  • 相关阅读:
    【bzoj3676】[Apio2014]回文串 —— 回文自动机的学习
    树链剖分求LCA
    读入输出优化
    【bzoj3124】[Sdoi2013]直径
    【codevs2183】匹配字符串
    【codevs2011】【LNOI2013】最小距离之和
    【codevs1306】广播操的游戏
    【hdu3966】Aragorn's Story
    【hdu3518】Boring counting
    C++-HDU3400-Line belt[三分]
  • 原文地址:https://www.cnblogs.com/daklqw/p/10414971.html
Copyright © 2011-2022 走看看