CF1041F Ray in the tube

挂上Chester大神的解题报告  

有一个思维跳跃的地方,就是不应该枚举所有的$B$点,而是应该在选定一个$A$点之后枚举距离计算。

然后我们发现枚举距离是$2^k$的长度就可以了,证明如下:

假如距离$d = 2^k$,那么对于每一个$A$点如果能被经过$a_p$的点弹到,需要满足$a_iequiv 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
", ans);
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/CzxingcHen/p/9673505.html