OVSolitario-io

导航

羊蹄

cf104679E埃式筛法+前缀和
前置知识:筛法
问题:对于节点为 1..N,若两个数有公共质因子(gcd(a, b) > 1)则在它们之间连一条无向边。问哪些点与 2 不连通?


数x与其最小质因子p连通(p ↔ x),当其与2不连通时,可以找到一中间点(同时包含2和p两个质因子(2 ↔ 2p ↔ p)) 则有:2 ↔ 2p ↔ p ↔ x

所以当2p<N即连通(p > N/2,则2p > N)

p为最小质因子, x = p * q(p <= q), 显然p^2 <= x, 若存在p > N/2,则相应的p^2 > (N/2)^2, 除p自身(质数)还在范围内, 都超出范围

对于N/2,N区间,p>N/2只有的质因子本身符合,会被留下,而其余会被p<N/2筛掉

发现:

  • 能连到 2 的数:存在质因子 p ≤ N/2;

  • 不能连到 2 的数:所有质因子都 > N/2;

即求(N/2, N] 的质数个数,以及N较小时的特殊讨论

点击查看代码
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    int M = 1e7;

    vector<int> is_prime(M + 1, 1);
    is_prime[0] = 0, is_prime[1] = 0;

    for (int i = 2; i <= M; i ++) {
        if (is_prime[i]) {
            for (int j = i * 2; j <= M; j += i) {
                is_prime[j] = 0;
            }
        }
    }

    for (int i = 1; i <= M; i ++) {
        is_prime[i] += is_prime[i - 1];
    }

    int t;
    cin >> t;

    while (t --) {
        int n;
        cin >> n;

        if (n <= 3) cout << n - 2 << '\n';
        else cout << is_prime[n] - is_prime[n / 2] << '\n';
    }

    return 0;
}

cf104679F位运算构造
前置知识:#算数基本定律


对于最终值,所有数的二进制位都只能是a的子集(包含b),OR操作取allx的子集,算出的XOR结果和b计算差别。

取奇数个1时XOR取1,但a取0时明显有0个1(即b位上的那个特殊1无法改动,所以b也为a子集)

XOR差别也一定也是a的子集,删去差别对应的(子集中)那个数,再检查或和是否满足条件即可(因为异或和已经满足条件了)

差异diff:

x(a的XOR和) ^ b = k(k属于集合a),求出的k即差异
点击查看代码
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    int t;
    cin >> t;

    while (t --) {
        int a, b;
        cin >> a >> b;

        if ((a | b) != a) cout << -1 << '\n';//b应为a子集
        else if ((a & -a) == a && b == 0 && a) {//a为2的幂且想让b == 0时,无解
            cout << -1 << '\n';
        }
        else {
            vector<int> ans;
            int xor_val = b;

            for (int i = 0; i <= a; i ++) {
                if ((i & a) == i) {//i为a子集
                    ans.emplace_back(i);
                    xor_val ^= i;//最终为b ^ all子集
                }
            }

            int ans_len = ans.size();
            if (!xor_val) xor_val = -1;//取0时满足,标记为-1
            else ans_len --;//否则需要删除一个数,个数-1

            cout << ans_len << '\n';
            for (auto &x: ans) {
                if(x != xor_val) {//输出其余留下的数
                    cout << x << ' ';
                }
                cout << '\n';
            } 
        }
    }

    return 0;
}

特判掉a为2的幂,且b = 0情况(无解)

其中只有 2 的幂才会满足它自己与其相反数 -a 相与等于自己,即 a 只有一位二进制 1,b == 0想让 XOR 的结果为 0(且判断a,排除a=0的情况)

发现有4=(100),子集为{0, 4},想让 OR = a (即 4),必须选上 4,但选上 4 时,XOR ≠ 0;
如果不选 4,OR 就变成 0 ≠ 4→ ❌ 所以完全无解。

cf104328D树上DP
C++14[lambda自递归]:lambda自递归


若合数x能整除all路径上点,则x的质因子也必然可以,只需要对那些质数p(p可整除的节点数>N/2)的方案去做判断

此时对树上节点进行染色分为两类:

  • p 整除的节点标记为白色
  • 其余为黑色

问题变为是否存在一条长为N/2的路径:维护每个点往下的最长的白色路径长度,看能否凑出长度超过N/2的路径即可

点击查看代码
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    int M = 1e7;
    vector<int> prime_factor(M + 1);
    iota(prime_factor.begin(), prime_factor.end(), 0);

    for (int i = 2; i <= M; i ++) {
        if (prime_factor[i] == i) {
            for (int j = i; j <= M; j += i) {
                prime_factor[j] = i;
            }
        }
    }

    int n;
    cin >> n;

    vector<int> nums(n);
    for (auto &x: nums) cin >> x;

    vector<vector<int>> path(n);
    for (int i = 0; i < n - 1; i ++) {
        int u, v;
        cin >> u >> v;
        u --, v --;
        path[u].emplace_back(v);
        path[v].emplace_back(u);
    }

    vector<int> cnt(M + 1, 0);

    for (auto &x: nums) {
        int vx = x;
        while (vx > 1) {
            int p = prime_factor[vx];
            cnt[p] ++;
            while (vx % p == 0) vx /= p;
        }
    }

    int to_check, max_len;
    vector<int> dp(n);

    auto dfs = [&] (auto &self, int u, int p) -> void {
        int v1 = 0, v2 = 0;

        for (auto &v: path[u]) {
            if (v != p) {
                self(self, v, u);
                if (dp[v] > v1) swap(v1, v2), v1 = dp[v];
                else if (dp[v] > v2) v2 = dp[v];
            }
        }

        if (nums[u] % to_check == 0) {
            max_len = max(max_len, v1 + v2 + 1);
            dp[u] = v1 + 1;
        }
    };

    for (int i = 0; i <= M; i ++) {
        if (cnt[i] * 2 > n) {
            to_check = i, max_len = 0;
            dfs(dfs, 0, -1);
            if (max_len * 2 > n) return cout << "YES", 0;
        }
    }

    cout << "NO";

    return 0;
}

H. Beacon Towers
所有分割点只可能出现在两个前缀最大值之间。

且其间最多只能插入一个分割点,所以假设中间有 k个分割点,可以任选一个分割,或者不选,因此有 k+1种方案

+1为不选(不选也为答案)

posted on 2025-10-08 15:46  TBeauty  阅读(23)  评论(0)    收藏  举报