将白色看作 \(0\),黑色看作 \(1\),并将所有人等距离排在圆上,若知道所有人颜色的异或和,就可以根据自己看见的颜色集合判断自己的颜色,且将圆等切为两半一定有少的一边的人数 \(\ge \lfloor \frac{n-1}{2} \rfloor\),但若圆两边的黑点关于切线翻转对称(如下图),则会出现看到颜色相同的两人策略不同,而不满足这是确定性策略
记 \(\vec{v}\) 表示所有黑点所在位置的矢量和并将其认为是切线,即 \(\vec{v}\) 逆时针左侧的点认为异或和为 \(1\),右侧的点认为异或和为 \(0\),那么两个关于切线翻转对称的黑点的矢量和将会抵消,若 \(\vec{v} \neq \vec{0}\) 则一定满足条件,否则若第 \(i\) 个人看到的黑点矢量和 \(\vec{v'}\) 与自己共线则猜黑色,否则猜白色
实现时记当前这个人在 \((1,0)\),记 \(s=\sum\limits_{i=0}^{n-2} a_i\),\(x=\sum\limits_{i=0}^{n-2} a_i \cos(\dfrac{2\pi(i+1)}{n})\),\(y=\sum\limits_{i=0}^{n-2} a_i \sin(\dfrac{2\pi(i+1)}{n})\),那么策略为 \(\begin{cases} 0,x=y=0\\ 1,x\neq0 \wedge y=0\\ (s+1) \text{ mod } 2,y > 0\\ s \text{ mod } 2,y< 0\\ \end{cases}\)
#include<bits/stdc++.h>
#include"tmp.h"
using namespace std;
const double pi=acos(-1),eps=1e-8;
double s[65],c[65];
int n;
void init(int m,bool t,int p){n=m;for(int i=1;i<=n;i++) s[i]=sin(2*pi*i/n),c[i]=cos(2*pi*i/n);
}
bool guess(unsigned long long a,int w){double x=0,y=0;int m=0;for(int i=1;i<n;i++) if(a>>(i-1)&1) x+=c[i],y+=s[i],m^=1;if(fabs(x)<eps&&fabs(y)<eps) return 0;else if(fabs(y)<eps) return 1;else return (y>0)^m;
}