QOJ5090 妙妙題

zyxawa發表於2024-07-28

將白色看作 \(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;
}

相關文章