CF1041F Ray in the tube
挂上Chester大神的解题报告
有一个思维跳跃的地方,就是不应该枚举所有的$B$点,而是应该在选定一个$A$点之后枚举距离计算。
然后我们发现枚举距离是$2^k$的长度就可以了,证明如下:
假如距离$d = 2^k$,那么对于每一个$A$点如果能被经过$a_p$的点弹到,需要满足$a_i\equiv a_p\ (Mod \ 2d)$,而对所有的$B$点,如果能被经过$a_p$的点弹到,需要满足$b_i + d \equiv a_p \ (Mod \ 2d)$。
那么对于一些其他的距离,我们的$d = 2^k$的距离一定可以计算到$td$所包含的点,所以这样子就足够了。
那么这样我们就可以枚举$d$然后去检验了,因为$d$的个数是$log(1e9)$个,然后用一个$map$记录一下同余的个数有几个更新答案即可。
时间复杂度$O(nlognlog1e9)$。
Code:
#include <cstdio> #include <cstring> #include <map> using namespace std; const int N = 1e5 + 5; const int MaxN = (int)1e9; int n, m, ans = 2, a[N], b[N]; map <int, int> cnt; inline void read(int &X) { X = 0; char ch = 0; int op = 1; for(; ch > '9' || ch < '0'; ch = getchar()) if(ch == '-') op = -1; for(; ch >= '0' && ch <= '9'; ch = getchar()) X = (X << 3) + (X << 1) + ch - 48; X *= op; } inline void chkMax(int &x, int y) { if(y > x) x = y; } int main() { int y; read(n), read(y); for(int i = 1; i <= n; i++) read(a[i]); read(m), read(y); for(int i = 1; i <= m; i++) read(b[i]); for(int d = 1; d < MaxN; d <<= 1) { int P = d << 1; cnt.clear(); for(int i = 1; i <= n; i++) cnt[a[i] & (P - 1)]++; for(int i = 1; i <= m; i++) cnt[(b[i] + d) & (P - 1)]++; for(map <int, int> :: iterator it = cnt.begin(); it != cnt.end(); ++it) chkMax(ans, it -> second); } printf("%d\n", ans); return 0; }