题解 CF768E 【Game of Stones】

Forever_Pursuit

2020-12-31 13:05:58

Solution

垃圾做法喜提 luogu 时间最劣解+空间最劣解+代码长度最劣解。 考虑状压,第 $i$ 位为 $1$ 表示之前某次已经取过了 $i$ 个石子, 设 $sg_{i,j}$ 表示当前剩 $i$ 个石子,状态为 $j$ 的 $sg$ 值, 虽然一共有 $2^{60}$ 种状态,但是其中真正有效的却不多,对于某个状态,所有为 $1$ 的位的下标的和显然不能超过 $60$,否则为无效状态, 可以写一个 dfs 搜出所有有效状态,发现只有 $101983$ 种, 于是可以对于所有有效的 $sg$ 暴力求 $mex$,时间复杂度为 $O(101983\times60^2)$,即可得到所有 $sg_{i,j}$,答案即为 $sg_{a_i,0}$ 的 $xor$, 实现时可以给每个有效状态分配一个下标,用 `unordered_map` 映射回去。 ```cpp #include<bits/stdc++.h> using namespace std; #define ull unsigned long long #define N 60 int read(){ int w=0,f=1; char c=' '; while(c<'0'||c>'9')c=getchar(),f=c=='-'?-1:f; while(c>='0'&&c<='9')w=w*10+c-48,c=getchar(); return w*f; } int n,sg[N+1][102000],sum[102000],cnt; ull vis[102000],fl,ind[N+1],all=ULONG_LONG_MAX; unordered_map<ull,int>mp; bool ap[N+1]; void dfs(int now,int s){ if(s>N)return; if(now==N)return vis[++cnt]=fl,sum[cnt]=s,mp[fl]=cnt,void(); now++; fl&=ind[now]; dfs(now,s); fl|=(1llu<<now); dfs(now,s+now); } void init(){ for(int i=1;i<=N;i++) ind[i]=all^(1llu<<i); dfs(0,0); for(int i=1;i<=N;i++){ for(int j=1;j<=cnt;j++){ if(sum[j]+i>N)continue; memset(ap,0,sizeof(ap)); for(int k=1;k<=N;k++) if(!(vis[j]>>k&1)&&i-k>=0)ap[sg[i-k][mp[vis[j]|1llu<<k]]]=1; for(int k=0;;k++) if(!ap[k]){ sg[i][j]=k; break; } } } } signed main(){ init(); n=read(); int ans=0; for(int i=1;i<=n;i++) ans^=sg[read()][1];//显然mp[0]=1 puts(ans?"NO":"YES"); return 0; } ```