Codeforces | CF1041F 【Ray in the tube】

昨天晚上全机房集体开\(Div2\),因为人傻挂两次\(B\)题的我开场就\(rank2000+\dots qwq\)于是慌乱之中的我就开始胡乱看题(口胡),于是看了\(F\dots\)(全机房似乎也就我一个人慌到心态爆炸)
起初想到的只有\(n^2\)的暴力,然而复杂度显然炸了,于是试图寻找规律,但是只想到一个假结论:忽略\(y\),然后取上面坐标为奇数的点数与下面坐标为偶数的点数的和与上面坐标为偶数的点数与下面坐标为奇数的点数的和,也即步长为\(1\)
但是显然这样过不了样例啊(上面的方法输出\(2\dots\)然而答案是\(3\)),因为没有考虑在上面和下面选的点的坐标奇偶性相同的情况,也即步长为\(2k(k\in N_+)\)的情况,但是如果要枚举\(\forall k\in [1,5\cdot10^8]\)的话显然复杂度还是不对,于是切\(F\)题的幻想就此破灭\(qwq\)(所以我把CD都切了(逃))
于是经过一番仔\((can)\)\((kao)\)\((ti)\)\((jie)\)发现只需要枚举步长为\(2^i(i\in[0,29])\)即可且\(y\)坐标可以忽略,证明如下:
\(y\)坐标可以忽略的解释:考虑\(y\)坐标在步长一定时只会影响\(ray\)的斜率,而反射时斜率取相反数,所以显然在\(y\)坐标差一定的情况下,步长总是定值,反射点也总是固定的(口胡),所以不妨忽略\(y\)坐标的影响(可以画图模拟一下)
假设步长不为\(2^k(k\in N)\)则一定可以表示为\(2^l\cdot (2p+1)(l,p\in N)\),此时我们作出从某一点出发步长分别为\(2^l,2^l\cdot(2p+1)(l,p\in N)\)\(ray\)的路径图像(假设此时\(l=1,p=3\),点\((2,0)\)是两条\(ray\)的一个公共点,则步长分别为\(2,6\))

不难发现在步长不等于\(2^l(l\in N)\)时,步长为\(2^l\cdot (2p+1)(l,p\in N)\)\(ray\)的反射点与步长为\(2^l\)\(ray\)的反射点完全重合且反射点密度小于步长为\(2^l\)\(ray\)的反射点密度,所以对于所有步长非\(2^k(k\in N)\)\(ray\)一定会存在一个更优解使得\(ans\)更大,由此可得只需判断步长为\(2^k(k\in N)\)的情况即可
所以正解就是枚举对于所有的出发点,步长为\(2^i(i\in[0,29])\)的情况,对所有的\(ans\)\(max\)即可,每次枚举\(i\)对所有坐标分上下对\(2^{i+1}\)取模分类,用\(map\)存余数为\(r(r\in[0,2^{i+1}-1])\)的坐标个数,时间复杂度为\(O((log10^9)\cdot(n+m))\)
\(AC\)代码\(\downarrow\downarrow\downarrow\)

#include<cstdio>//CF1041F
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#include<map>

using namespace std;

const int N=1e5+5;

int n,m,y,a[N],b[N],base2[31],ans,LUOGU;

void solve(int u){
    map<int,int>cntd,cntu;
    int mod=base2[u+1];
    for(int i=1;i<=n;i++){
        cntd[a[i]%mod]++;
    }
    for(int i=1;i<=m;i++){
        cntu[b[i]%mod]++;
    }
    for(int i=1;i<=n;i++){
        ans=max(ans,cntd[a[i]%mod]+cntu[(a[i]+base2[u])%mod]);
    }
    for(int i=1;i<=m;i++){
        ans=max(ans,cntu[b[i]%mod]+cntd[(b[i]+base2[u])%mod]);
    }
}

int main(){
    for(int i=0;i<=30;i++){
        base2[i]=(1<<i);
    }
    scanf("%d%d",&n,&y);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    scanf("%d%d",&m,&y);
    for(int i=1;i<=m;i++){
        scanf("%d",&b[i]);
    }
    for(int i=0;i<=29;i++){
        solve(i);
    }
    printf("%d\n",max(ans,2));
    return 0;
}
posted @ 2018-09-17 09:30  __BLUESKY007  阅读(739)  评论(0编辑  收藏  举报