zoukankan      html  css  js  c++  java
  • CF1041F Ray in the tube

    首先 y 肯定是没用的

    看到数据范围,

    二分?没啥好二分的

    dp ? 反正我的状态是存不下的

    于是开始手玩

    先看看符合条件的点集有什么限制

    设点s1, s2, s3, ..., sn 能被同一条射线照到

    则它们之间的坐标关系应该以下两条中的一个满足:

    1. s2 - s1 = s3 - s2
    2. s2 - s1 = 2(s3 - s2)

    观察上面的式子,与它在同一列的点和它的关系满足条件 1 ,
    不同列的点和它的关系满足条件 2

    那么其实就是求这个式子:

      maxnx=1 {∑xi=1[(sx - si) / 2 = (2 * k + 1) * Δ] + ∑xj=1[(sx - sj) / 2 = 2 * k * Δ]}

    又经过长时间的手玩,突然想到,我应该会有一些方案是一定劣于另一些方案的

    比如 Δx = 3, 它就不如 Δx = 1 要优,
    因为 Δx = 3 的方案选出来的点是 Δx = 1 的方案选出来的点的真子集

    考虑若要一个方案比当前某个方案劣的话, 则它选出来的点是当前方案选的点的真子集,
    而要满足这个条件的话,
    设当前方案每一次反射 x 坐标偏移量为 Δx ,那么这个劣的方案的 Δx' = (2 * k + 1) * Δx

    联想到 bzoj2734集合选数 的构造的方式,列出以下矩阵:

    1, 3, 5, 7, 9, 11, 13, 15...

    2, 6, 10, 14, 18, 22, 26, 30, ...

    4, 12, 20, 28, 36, 44, 52, 60, ...

    ...

    多画几次认为上面的矩阵是没有问题的,相邻两行的方案之间没有包含关系

    其实有意义的 Δx 就是 1, 2, 4, 8, ...

    所以有意义的 Δx 只有 log(1e9) 个

    考虑 dp,空间可行,并不会转移,也不会预处理

    于是做到这里我就弃疗了... => 以下来思路自题解

    对于固定的 Δx ,同一列的能作为答案的点集在模 Δx 意义下是同余的
    那么对于不同列的点,其实它们的坐标减去或加上一个 Δx 就和另一列的点坐标相同了

    所以我们就可以在 O(n*logn*log(1e9)) 的时间内做这道题了

    log(1e9) 的枚举 Δx = 2^i

    之后 nlogn 的将每个数模 Δx ,钦定一列是加(减容易出锅) Δx 之后再模的
    将结果 哈希/离散化/map 存一下每次 ++计数器 统计一个 max 就好了

    根本没往模那想,显然对于一些等差的东西,模公差是同余的


     代码:

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<cctype>
    #include<cstdio>
    #include<map>
    using namespace std;
    
    const int MAXN = 100005;
    
    int n[2], y[2];
    int x[2][MAXN];
    
    inline int rd() {
        register int x = 0;
        register char c = getchar();
        while(!isdigit(c)) c = getchar();
        while(isdigit(c)) {
            x = x * 10 + (c ^ 48);
            c = getchar();
        }
        return x;
    }
    inline void init() {
        for(int i = 0; i < 2; ++i) {
            n[i] = rd(); y[i] = rd();
            for(int j = 1; j <= n[i]; ++j) x[i][j] = rd();
        }
        return;
    }
    
    int main() {
        init();
        if(n[0] == n[1] && n[0] == 1 && x[0][1] == x[1][1]) {
            puts("2");
            return 0;
        }
        int ans = 0;
        for(int i = 1; i <= 1000000000; i <<= 1) {
            int dlt = (i << 1);
            map<int,int> mp;
            for(int j = 0; j < 2; ++j) {
                int pls = (j ? i : 0);
                for(int k = 1; k <= n[j]; ++k) {
                    ++mp[(x[j][k] + pls) % dlt];
                }
            }
            for(map<int,int>::iterator it = mp.begin(); it != mp.end(); ++it) ans = max(ans, it->second);
        }
        printf("%d
    ", ans);
        return 0;
    }
    

     题解中证明只有 log(1e9) 个有意义的 Δx 方式是反证

    令 Δx = m * 2^i 且 m 为奇数

    其实这个方案选的点在 Δx' = Δx / m 的方案中也都选了

    听起来比我的证明更加理性一些

  • 相关阅读:
    C# 关于调用微信接口的代码
    Winform实现微信功能
    Delphi 7 在IDE菜单中增加UPX工具
    Delphi7中Unicode,ANSI,UTF编码问题
    本机时间不正确带来的问题
    Delphi最简化异步选择TCP服务器
    C# Winform小程序:局域网设置NTP服务器、实现时间同步
    开源Inno Setup官网下载、安装、打包教程(官网安装向导中文语言包)
    css 雪碧图的制作
    原生js 实现的瀑布流
  • 原文地址:https://www.cnblogs.com/xcysblog/p/9678678.html
Copyright © 2011-2022 走看看