1. 程式人生 > >【二進位制優化】Codeforces - 1041 - F. Ray in the tube

【二進位制優化】Codeforces - 1041 - F. Ray in the tube

題目連結<http://codeforces.com/contest/1041/problem/F>


題意:

在兩個反射面上取一點發射一道鐳射,兩個反射面上裝了一些感測器,問最多有幾個感測器能接收到鐳射。


題解:

首先,題目給出了反射面的縱座標,這是沒有用的,我們只需要考慮橫座標的距離即可。

然後總體思路是:

1)列舉步長。

2)處理出每個點在此步長下的狀態,並用map記錄每個狀態的數量。

3)再列舉起點(起點只需列舉感測器的位置)計算每個起點下的答案。

後面兩個複雜度是在1e5級別的,而第一個的複雜度能夠達到1e9。

仔細推敲或者參考題解後就可以發現,步長只需列舉2^{l}

的情況,這樣複雜度可以降到30。

簡單證明一下,如果步長不是2^{l},那麼步長可以化為2^{l}*(2*x+1)的形式,很容易發現前者是包含後者的,如果在圖上進行模擬的話會更清晰。


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+7;
int n,m,y,a[N],b[N];
map<int,int>aa,bb;
int main(){
    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]);
    int ans=0;
    if(n) ans++;if(m) ans++;
    int mod=2;
    for(int k=2;k<=30;k++){
        aa.clear(),bb.clear();
        for(int i=1;i<=n;i++)
            aa[a[i]%mod]++;
        for(int i=1;i<=m;i++)
            bb[b[i]%mod]++;
        for(int i=1;i<=n;i++)
            ans=max(ans,aa[a[i]%mod]+bb[(a[i]%mod+mod/2)%mod]);
        for(int i=1;i<=m;i++)
            ans=max(ans,bb[b[i]%mod]+aa[(b[i]%mod+mod/2)%mod]);
        mod*=2;
    }
    printf("%d\n",ans);
    return 0;
}