原题链接:http://codeforces.com/contest/1041/problem/F
Ray in the tube
You are given a tube which is reflective inside represented as two non-coinciding, but parallel to lines. Each line has some special integer points — positions of sensors on sides of the tube.
You are going to emit a laser ray in the tube. To do so, you have to choose two integer points and on the first and the second line respectively (coordinates can be negative): the point is responsible for the position of the laser, and the point — for the direction of the laser ray. The laser ray is a ray starting at and directed at which will reflect from the sides of the tube (it doesn’t matter if there are any sensors at a reflection point or not). A sensor will only register the ray if the ray hits exactly at the position of the sensor.
Examples of laser rays. Note that image contains two examples. The sensors (denoted by black bold points on the tube sides) will register the blue ray but only will register the red.
Calculate the maximum number of sensors which can register your ray if you choose points and on the first and the second lines respectively.
Input
The first line contains two integers and — number of sensors on the first line and its coordinate.
The second line contains integers — coordinates of the sensors on the first line in the ascending order.
The third line contains two integers and — number of sensors on the second line and its coordinate.
The fourth line contains integers — coordinates of the sensors on the second line in the ascending order.
Output
Print the only integer — the maximum number of sensors which can register the ray.
Example
input
3 1
1 5 6
1 3
3
output
3
Note
One of the solutions illustrated on the image by pair and .
题解
如果在实数域做的话,我们可以从一个无限接近于 的角度发出射线,这样整个管子都是射线岂不是很棒?
然而放到整数域的话,我们能做到的最极限角度就是步长为 了,这样由于反射问题,在同一侧管壁上射线就是两个点两个点的跳的,导致有一半的整点达不到:
谁能填这些空呢?我们试试步长为 的射线:
发现只填了一半的空,再试试步长为 的,发现被步长为 完虐,而步长为 的射线又可以填掉一半的空。。。以此类推,可以发现只有步长为 的射线可以到达一些其他线到不了的点,除此之外的步长都严格劣于 (即其他步长能到达的点集都会被一个步长为 的射线能到达的点集严格包含)。
那么我们就只需要枚举步长为 的射线了,对于同侧的点,只要 二倍步长同余就说明在同一射线上,对于异侧的点则需要先加上步长再取模。
由于模数较大而 很小,可以用 来统计。
代码
学习了一波读入姿势,感觉很强。
#include<bits/stdc++.h>
using namespace std;
const int M=1e5+5;
int up[M],down[M],ans=2,n,m;
map<int,int>mp;
void in(){scanf("%d%*d",&n);for(int i=1;i<=n;++i)scanf("%d",&up[i]);scanf("%d%*d",&m);for(int i=1;i<=m;++i)scanf("%d",&down[i]);}
void ac()
{
for(int d=2;d<=1e9;d<<=1)
{
mp.clear();
for(int i=1;i<=n;++i)++mp[up[i]%d],ans=max(ans,mp[up[i]%d]);
for(int i=1;i<=m;++i)++mp[(down[i]+(d>>1))%d],ans=max(ans,mp[(down[i]+(d>>1))%d]);
}
printf("%d",ans);
}
int main(){in();ac();}