QOJ5090 妙妙题

将白色看作 \(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;
}
posted @ 2024-07-28 11:53  zyxawa  阅读(50)  评论(0)    收藏  举报