• 【洛谷P5675】取石子游戏


    题目

    题目链接:https://www.luogu.com.cn/problem/P5675
    Alice 和 Bob 在玩一个古老的游戏。现在有若干堆石子,Alice 和 Bob 轮流取,每次可以选择其中某一堆的石子中取出任意颗石子,但不能不取,谁先取完使得另一个人不能取了算赢。

    现在场地上有\(N\)堆石子,编号为 \(1\)\(N\)。Alice 很快发现了这个游戏存在一些固定的策略。阴险的 Alice 想赢得这场比赛就来找到主办方你,希望你在这 \(N\) 堆石子中选出若干堆石子作为最后游戏用的石子堆并使得 Alice 能获得胜利。你自然不想让 Alice 得逞,所以你提出了一个条件:Alice 在这个游戏中第一次取的那堆石子的编号需要你来指定(仅指定取的石子堆编号,不指定第一次取多少个,这个指定的石子堆必然包含在最后游戏用的石子堆中)。

    现在你很好奇,你想算算有多少种方案让 Alice 不能获胜。注意,即使选出的石子堆的编号的集合完全相同,指定第一次取的石子堆的编号不同,也认为方案是不同的。

    思路

    \(f[i][j]\) 表示前 \(i\) 个数字取了若干个异或和为 \(j\) 的方案数,\(g[i][j]\) 表示第 \(i\) 个数以后取若干个数异或和为 \(j\) 的方案数。
    枚举每一个位置作为选择的石子堆,假设其他石子的异或和为 \(k\),那么我们只需要满足无论这堆石子取多少,都有 \(k \operatorname{xor}\) 取的石子数 \(\neq 0\)。也就是需要满足 \(k\geq a_i\)
    直接无脑 \(O(nA^2)\) 统计答案即可。其中 \(A\) 表示 \(a\) 的上限。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N=260,MOD=1e9+7;
    int n,ans,a[N],f[N][N],g[N][N];
    
    int main()
    {
    	scanf("%d",&n);
    	for (int i=1;i<=n;i++)
    		scanf("%d",&a[i]);
    	f[0][0]=g[n+1][0]=1;
    	for (int i=1;i<=n;i++)
    		for (int j=0;j<=255;j++)
    			f[i][j]=(f[i-1][j]+f[i-1][j^a[i]])%MOD;
    	for (int i=n;i>=1;i--)
    		for (int j=0;j<=255;j++)
    			g[i][j]=(g[i+1][j]+g[i+1][j^a[i]])%MOD;
    	for (int i=1;i<=n;i++)
    		for (int j=0;j<=255;j++)
    			for (int k=0;k<=255;k++)
    				if ((j^k)>=a[i])
    					ans=(ans+1LL*f[i-1][j]*g[i+1][k])%MOD;
    	printf("%d",ans);
    	return 0;
    }
    
  • 相关阅读:
    冲刺阶段站立会议每日任务3
    冲刺阶段站立会议每日任务2
    典型场景描述
    冲刺阶段站立会议每天任务1
    第七周学习进度
    第六周学习进度
    四则运算网页版
    团队项目简介(1000字)
    返回一个二维整数数组中最大联通子数组的和
    本周学习进度
  • 原文地址:https://www.cnblogs.com/stoorz/p/13805461.html
Copyright © 2020-2023  润新知