首页 > 其他分享 >CF364D Ghd 题解

CF364D Ghd 题解

时间:2023-09-27 20:35:32浏览次数:40  
标签:10 cnt ch int 题解 因数 Ghd CF364D 枚举

CF364D Ghd 题解

题目大意

给定一个长度为 \(n\) 的序列 ,你需要从中选出一个元素个数不少于 \(\left\lceil{\frac{n}{2}}\right\rceil\) 的子序列,使得这个子序列中所有元素的 \(\gcd\) 最大。

分析

数据范围吓人。

\(10^6\),但是根本想不到什么 \(O(n \log n)\) 或 \(O(n)\) 的算法。然后就开始想其他技巧。

刚开始想的是什么 \(\gcd\) 的性质,但是显然没有什么结果(我赛时就想到这里,然后寄了)。

注意到子序列元素个数比较大,可能比较容易从这入手,所以我们进一步从 \(\left\lceil{\frac{n}{2}}\right\rceil\) 这里分析。

题解

既然我们选至少一半,那么就意味着每一个数都有 \(\frac{1}{2}\) 的几率被选进最终答案的子集。我们可以考虑随机枚举几个数,假设我们枚举了 \(m\) 个数,那么至少有一个数在答案的子集里的概率为 \(1 - \frac{1}{2^m}\)。这个概率其实蛮大的。

然后我们去想对于每一个枚举的数,我们怎么算可能的答案。

如果这个数在最终的子集里,那么意味着最终的 \(\gcd\) 一定是这个数的一个因数。所以我们考虑枚举这个数的所有因数,然后算每个因数在原序列中的出现位置,最后从大到小找到第一个出现次数大于等于 \(\left\lceil{\frac{n}{2}}\right\rceil\) 的数,并与我们最终的 \(ans\) 取 \(\max\)。

实现方面的话,记 \(cnt_i\) 表示第 \(i\) 个因数在原序列中出现的次数。我们先对所有因数排序,然后从 \(1\) 到 \(n\) 枚举原序列的数,与我们当前随机出来的数求 \(\gcd\),求出来以后在存因数的那个数组里 \(\operatorname{lower\_bound}\) 找(二分也行),使其 \(cnt + 1\)。但是这样明显是不对的,因为如果两个数的 \(\gcd\) 为 \(3\),那么不仅 \(3\) 的出现次数加一,\(6, 9\) 这一类数的出现次数也会多一次。所以我们最后求完 \(cnt\) 后再枚举一遍因数那个数组,然后对于每个因数 \(i\),再去枚举一遍小于它的因数 \(j\),如果 \(i \bmod j = 0\),那么令 \(cnt_i\) 加上 \(cnt_j\),这才是最终的 \(cnt\)。

总时间复杂度 \(O(n \log d + d^2)\) 差不多。\(d\) 代表因数个数,其实蛮小的,对于 \(10^{12}\) 以内的数,最多的因数个数也才 \(6720\)。\(m\) 就是我代码里的 \(T\),我取的 \(10\),一发 AC 了,\(3.5s\),没什么问题。

代码

如果你能看懂我用的随机化更好,看不懂就用普通的 \(rand()\) 函数就行。

#include <bits/stdc++.h>
#define int long long
#define M 1000005
#define mod 1000000007
#define time() chrono::system_clock::now().time_since_epoch().count()

using namespace std;

inline int read() {
    int x = 0, s = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9') {
        if(ch == '-')
            s = -s;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9') {
        x = (x << 3) + (x << 1) + ch - '0';
        ch = getchar();
    }
    return x * s;
}

void write(int x) {
    if(x < 0)  {
        x = ~(x - 1);
        putchar('-');
    }
    if(x > 9)
        write(x / 10);
    putchar(x % 10 + 48);
}

int n, a[M], ans, d[M >> 2], cnt[M >> 2];

signed main() {
    n = read();
    for(int i = 1; i <= n; ++ i)
        a[i] = read();
    int T = 10;
	default_random_engine e;
	uniform_int_distribution<int> Z(1, n);
	srand(time());
	e.seed(rand());
    for(int t = 1; t <= T; ++ t) {
        int r = Z(e);
        int len = 0;
        int x = a[r];
        int sq = sqrt(x);
        for(int i = 1; i <= sq; ++ i)
            if(x % i == 0)
                d[++ len] = i, cnt[len] = 0, d[++ len] = x / i, cnt[len] = 0;
        if(sq * sq == x)
            -- len;
        stable_sort(d + 1, d + 1 + len);
        for(int i = 1; i <= n; ++ i)
            ++ cnt[lower_bound(d + 1, d + 1 + len, __gcd(x, a[i])) - d];
        for(int i = 1; i <= len; ++ i)
            for(int j = i + 1; j <= len; ++ j)
                if(d[j] % d[i] == 0)
                    cnt[i] += cnt[j];
        for(int i = len; i >= 1; -- i) {
            if(cnt[i] * 2 >= n) {
                ans = max(ans, d[i]);
                break;
            }
        }
    }
    write(ans);
}

/*
10
1 2 3 4 5 6 7 8 9 10
*/

标签:10,cnt,ch,int,题解,因数,Ghd,CF364D,枚举
From: https://www.cnblogs.com/Meteor-streaking/p/17734246.html

相关文章

  • [ARC125B] Squares 题解
    题意给定正整数\(N\),求满足如下条件的正整数对\((x,y)\)的数量:\(1\lex,y\leN\)\(x^2-y\)为完全平方数(\(0\)也是完全平方数)(\(1\leN\le10^{12}\))。题解因为\(x^2-y\)为完全平方数,设其为\(z^2\),那么有\[\begin{aligned}x^2-y=z^2\\\end{al......
  • [题解] Codeforces Round 900(Div.3) E~F
    CodeforcesRound900(Div.3)E~FE.Iva&Pav因为按位与的结果不会随着越多数字的增加而增加,因此我们可以利用这个性质二分出右端点,只需要一个可以查询区间的数据结构即可。或者是按位考虑第\(i\)个数字的第\(k\)位,后缀最近的\(0\)的位置,按位考虑也可以。但是这题使用二分......
  • ACAM 学习笔记 | 附 YbtOJ 全部题解
    怎么有人现在才学ACAM呢。好像比SAM简单挺多啊,也不记得当时是哪里看不懂。AC自动机(✔)自动AC机(✘)概述ACAM(Aho–CorasickAutomaton),是用来解决多模式串匹配的字符串算法。它的结构是个DAG,其中点表示状态,边表示转移。这一点上各种自动机都是相同的。具体来说,可以感性......
  • [题解]CF1878E Iva & Pav
    CF是没题考了吧,每场都出二进制拆位。思路首先我们可以二分\(r\),因为\(r\)越大,按位与一定只会小于等于\(r\)小的情况。那么,我们可以用\(num_{i,j}\)记录\(a_j\)第\(i\)位的二进制情况。如果我们对\(num_{i,j}\)做一个前缀和,如果\(num_{i,r}-num_{i,l-1}=r......
  • 安装 SonarQube后sonarqube-sonarqube无法启动的问题解决
    1.前言我的环境:k8s集群(version1.23.6),安装了Kubesphere(versionv3.4)作为可视化界面,最近想要推动团队走CICD,于是在Kubesphere中启用了devops组件,参考:https://kubesphere.io/zh/docs/v3.4/pluggable-components/devops/。组件安装完成后,需要将Sonarqube集成到流水线中,于是又安装......
  • luogu P4819 [中山市选] 杀人游戏 题解 【强连通分量+缩点】
    目录题目链接思路分析代码题目链接P4819思路分析首先考虑这道题的连通性。容易发现这种类型的题目会容易产生环形的状态转移。假设我们知道了其中的一个点是否是黑白点,那么我们就可以知道所有点是否是黑白点。容易陷入一个误区:我们只能通过一个点知道他所相邻的最直接的点,如何......
  • CF1878 A-G 题解
    前言赛时代码可能比较难看。A判定\(a\)中是否有\(k\)即可。赛时代码B奇怪的构造题。令\(a_1=1,a_2=3\),其他项由上一项加一开始枚举判定可行性即可,可以简单证明时间复杂度为\(O(n)\)。赛时代码C容易发现当\(x\in\left[\dfrac{k(k+1)}{2},\dfrac{k(2n-k+1)}{2}\ri......
  • 【UVA 536】Tree Recovery 题解(根据遍历序列还原二叉树)
    小瓦伦丁非常喜欢玩二叉树。她最喜欢的游戏是随机构建查找节点中带有大写字母的二叉树。这是她创作的一个例子:为了给后代记录她的树,她为每棵树写下了两个字符串:预订单遍历(根、左子树、右子树)和有序遍历(左子树、根、右子树。对于上面绘制的树,预序遍历是DBACEGF,有序遍历是ABCDEFG......
  • Codeforces Round 742 Div2 A-D题解
    CodeforcesRound742Div2A-D题解A.DominoDisaster这题就是说给出一些2x1tile,然后给出2xn的第一行构造,问第二行这个刚开始想着是啥dp,一看那么多人过了果断改思路,发现这题就是个模拟题,就是把U换成D,D换成U,L和R不影响,然后输出就行了代码#include<bits/stdc++.h>using......
  • P6411 [COCI2008-2009#3] MATRICA 题解
    水题。发现根据限制\(M_{i,j}=M_{j,i}\)可以知道除了主对角线上的点,其他的点都是成对出现的。也就是说如果有一条要求的\(a_i\)为奇数,那么至少有一个\(c_i\)在主对角线上。记\(S=\sum\limits_{i=1}^{k}(a_i\equiv1\pmod2)\),即有\(S\)个要求中\(a_i\)为奇数。主对......