题意:有n个堆,每个堆的高度为pi,两人玩游戏,每次可以任选一堆,并选择小于此堆的高度h(h<=pi)把这堆分离成高度为h的堆和高度为pi%h的堆。堆高为1时,是不可再分的。问:先手赢还是后手赢。
题解:
SG函数,我们先预处理前2000的SG函数。这里每次求SG值时,后继状态(一个堆分为多个堆)我们是异或的,不像之前的(一个堆就分为一个堆)就 直接标记下后继状态。为什么呢?
之前状态转移是确定的,一堆转移后还是一堆(只是数量变了)可以直接确定转移后的SG函数值,现在是一堆转移成多堆,原来堆的sg函数就是分成各个自堆函数的异或和,这个可以根据SG定理可得:游戏和的SG函数等于各个游戏SG函数的Nim和,所以说把一个堆分成多个堆就是一个NIM游戏。后继状态就是各个子堆的异或和。

#include<iostream> #include<cstring> #include<cmath> #include<algorithm> #include<cstdio> #include<vector> #include<map> #include<set> #include<queue> #include<stack> //#define _for(i,a,b) for(int i=a;i<=b;i++) using namespace std; typedef long long ll; double eps=0.05; ll mod=1e9+7; const int INF=0x3f3f3f3f,inf =0x3f3f3f3f; const int MAXN=2e3+10; const int maxn = 1e7+10; //ll inf=100000000000000; //template<typename T>inline void read(T &x) //{ // x=0; // static int p;p=1; // static char c;c=getchar(); // while(!isdigit(c)){if(c=='-')p=-1;c=getchar();} // while(isdigit(c)) {x=(x<<1)+(x<<3)+(c-48);c=getchar();} // x*=p; //} typedef unsigned long long ull; const int N=1e5+7; const double PI=acos(-1.0); int SG[2010]; set<int> S; void init() { SG[1]=0; int tmp=0; for(int i=2;i<=2002;i++) { S.clear(); for(int j=1;j<i;j++) { tmp=0; if((i/j)&1) tmp^=SG[j];//偶数异或和为0,奇数为本身 if(i%j) tmp^=SG[i%j]; S.insert(tmp); } for(int j=0;;j++) { if(!S.count(j)){ SG[i]=j;break; } } } } int main() { init(); int n; scanf("%d",&n); int item,sum=0; for(int i=1;i<=n;i++) { scanf("%d",&item); sum^=SG[item]; } if(sum) puts("First"); else puts("Second"); return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律