CF1041F Ray in the tube

首先观察到给定的\(y\)是没用的,激光最终会射到哪些接收器只会被\(A\)\(B\)位置所影响。

\(A\)\(B\)点的位置被\(x_A\)\(|x_A-x_B|\)所决定。\(L=|x_A-x_B|\)

现在假设我们已经确定了\(x_A\),还要选择一个\(L\)。假如说我们选择了一个\(L\),并且存在一个大于一个的奇数\(k|L\),那么我们可以选择一个新的\(L'=\frac LK\),新的激光不仅会经过原来的关键点,还会多经过一些点。

如图

\(\vec{AC}\)就可以被\(\vec{AG}+\vec{GH}+\vec{HC}\)代替

所以我们选择的\(L\)不能被任意比一大的奇数整除,也就是说\(L=2^n\),这样的\(L\)最多有\(\log_210^9\)个,枚举算即可

对于一个固定的\(L\),我们还需要算最优的\(x_A\),观察在下面的关键点\(a_i\)如果满足\(|a_i-x_a|\equiv0(mod~~2L)\)则会被射中,上面的关键点满足\(b_i-x_a\equiv L(mod~~2L)\),则会被射中,所以开个\(map\),对于每个关键点让位置在\(mod~~2L\)意义下\(x_a++\)

注意特判\(x_a=x_b\),不然会反复纵跳

\(O(nlognlog10^9)\)

#include<cstdio>
#include<map>
using namespace std;
const int N = 2e5 + 5;
int a[N],b[N],n,m,ans = 0,emp;
map<int,int>mp;
void check(int x){
	mp.clear();
	for(int i = 1;i <= n;++i)
		++mp[a[i] % x];
	for(int i = 1;i <= m;++i)
		++mp[(b[i] + (x>>1)) % x];
	for(auto v:mp)
		ans = max(ans,v.second);
}
int main(){
	scanf("%d%d",&n,&emp);
	for(int i = 1;i <= n;++i)
		scanf("%d",&a[i]);
	scanf("%d%d",&m,&emp);
	for(int i = 1;i <= m;++i)
		scanf("%d",&b[i]);
	for(int i = 1;i <= n;++i)
		++mp[a[i]];
	for(int i = 1;i <= m;++i)
		++mp[b[i]];
	for(auto v:mp)
		ans = max(ans,v.second);
	for(int i = 1;i <= 30;++i)
		check(1<<i);
	printf("%d",ans); 
}
posted @ 2020-10-23 10:32  INFP  阅读(78)  评论(0编辑  收藏  举报