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 的方案中也都选了

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

  • 相关阅读:
    121. Best Time to Buy and Sell Stock
    70. Climbing Stairs
    647. Palindromic Substrings
    609. Find Duplicate File in System
    583. Delete Operation for Two Strings
    556 Next Greater Element III
    553. Optimal Division
    539. Minimum Time Difference
    537. Complex Number Multiplication
    227. Basic Calculator II
  • 原文地址:https://www.cnblogs.com/xcysblog/p/9678678.html
Copyright © 2011-2022 走看看