首页 > 其他分享 >GCD Counting

GCD Counting

时间:2024-10-16 20:00:22浏览次数:7  
标签:质因数 GCD int gcd MAXN mathcal Counting log

算法

\(\mathcal{O}(n \log n)\) 算法, \(95pts\)

观察题目,发现题目要求我们求 \(\gcd\) 不等于 \(1\) 的一条最长链
考虑将每个数分解质因数
对于每一个 \(1 \sim k\) 中的质数, 将所有含有这个质因子的数加入一颗虚树, 求最长链即可, 经过尝试发现 \(k = 700\) 时即可通过
可以用并查集维护连通块加速搜索, 时间复杂度中的 \(\log n\) 就是小常数并查集
但是这样子无法顾及到公因数很大的情况, 可以用 \(\rm{map}\) 维护要处理的质因数, 然后再来计算
但是我不想写了

代码

#include <bits/stdc++.h>
#define int long long
const int MAXN = 2e5 + 20;

int n;
int Val[MAXN];

struct node
{
    int to, next;
} Edge[MAXN << 1];
int head[MAXN];
int cnt = 0;

void init()
{
    for (int i = 1; i <= n; i++)
    {
        head[i] = -1;
    }
}

void addedge(int u, int v)
{
    Edge[++cnt].to = v;
    Edge[cnt].next = head[u];
    head[u] = cnt;
}

int Prime[MAXN];
int Vis[MAXN];
int Prime_cnt = 0;
void Euler(int x)
{
    memset(Vis, false, sizeof(Vis));
    memset(Prime, 0, sizeof(Prime));

    for (int i = 2; i <= x; i++)
    {
        if(!Vis[i])
            Prime[++Prime_cnt] = i;
        for (int j = 1; j <= Prime_cnt && i * Prime[j] <= x; j++)
        {
            Vis[i * Prime[j]] = true;
            if(i % Prime[j])
                break;
        }
    }
}

bool CanUse[MAXN];
bool vis[MAXN];
int dist[MAXN];

class Union_Set
{
    private:

    public:
        int fa[MAXN];
        void init()
        {
            for (int i = 1; i <= n; i++)
            {
                fa[i] = i;
            }
        }

        int find(int x)
        {
            return fa[x] = (fa[x] == x) ? fa[x] : find(fa[x]);
        }

        void merge(int u, int v)
        {
            int fa_u = find(u);
            int fa_v = find(v);
            fa[fa_u] = fa_v;
        }
} US;

void dfs1(int Now, int fa, int d)
{
    dist[Now] = d;
    vis[Now] = true;
    for (int i = head[Now]; ~i; i = Edge[i].next)
    {
        int Nowto = Edge[i].to;
        if (CanUse[Nowto] && Nowto != fa)
        {
            US.merge(Now, Nowto);
            dfs1(Nowto, Now, d + 1);
        }
    }
}

std::vector<int> Conect[MAXN];
int Conect_cnt = 0;
int Map[MAXN];

int Find_Longest_Road()
{
    memset(vis, false, sizeof(vis));
    US.init();
    for (int i = 1; i <= n; i++)
    {
        if (!vis[i] && CanUse[i])
        {
            dfs1(i, -1, 1);
        }
    }

    memset(vis, false, sizeof(vis));
    for (int i = 1; i <= Conect_cnt; i++)
    {
        Conect[i].clear();
    }
    Conect_cnt = 0;
    for (int i = 1; i <= n; i++)
    {
        if(!CanUse[i]) continue;
        if(!vis[US.find(i)])
        {
            vis[US.find(i)] = true;
            Conect[++Conect_cnt].push_back(i);
            Map[US.find(i)] = Conect_cnt;
        }else{
            Conect[Map[US.find(i)]].push_back(i);
        }
    }

    int Ans = 0;
    for (int i = 1; i <= Conect_cnt; i++)
    {
        int rt = 0;
        for (int j = 0; j < Conect[i].size(); j++)
        {
            if(dist[rt] < dist[Conect[i][j]])
            {
                rt = Conect[i][j];
            }
        }
        dfs1(rt, -1, 1);

        for (int j = 0; j < Conect[i].size(); j++)
        {
            Ans = std::max(Ans, dist[Conect[i][j]]);
        }
    }

    return Ans;
}

signed main()
{
    freopen("counting2.in", "r", stdin);
    //freopen("counting.out", "w", stdout);

    /*读入 + 建树*/
    scanf("%lld", &n);
    for (int i = 1; i <= n; i++)
        scanf("%lld", &Val[i]);

    init();
    for (int i = 1; i <= n - 1; i++)
    {
        int u, v;
        scanf("%lld %lld", &u, &v);

        addedge(u, v);
        addedge(v, u);
    }

    /*质数筛*/
    Euler(25);

    int Ans = 0;
    for (int i = 1; i <= Prime_cnt; i++)
    {
        int Now_Gcd = Prime[i];
        for (int j = 1; j <= n; j++)
        {
            if(Val[j] % Now_Gcd == 0)
            {
                CanUse[j] = true;
            }else{
                CanUse[j] = false;
            }
        }

        Ans = std::max(Ans, Find_Longest_Road());
    }

    for (int i = 1; i <= n; i++)
    {
        if(Val[i] != 1)
        {
            printf("%lld", Ans);
            return 0;
        }
    }
    printf("0");

    return 0;
}

/*
3
2 3 4
1 2
2 3

1
*/

/*
3
2 3 4
1 3
2 3

2
*/

/*
3
1 1 1
1 2
2 3

0
*/

总结

看到 \(\gcd\) 就要想分解质因数, 可以枚举 \(\gcd\) 的值从而解决问题

每道题目不一定要用一次操作进行完, 可以按照统一逻辑进行多次操作

\(\mathcal{O}(n)\) 算法

观察到这道题很像 树形 dp
于是去学了一下

容易发现 \(2 \times 10^5\) 内含有最多不同质因数的数量不超过 \(10\), 想到对每个数求质因数, 然后进行对含有相同质因数的进行转移
之前的 \(\mathcal{O}(n \log n)\) 算法需要找连通块之类的, 常数也不小, 而这一次我们想办法只在原图上进行操作, 略去了分图的时间复杂度 (类似于 分层图 \(\rightarrow\) dp 加一维)

标签:质因数,GCD,int,gcd,MAXN,mathcal,Counting,log
From: https://www.cnblogs.com/YzaCsp/p/18470094

相关文章

  • 【广西省赛#7】G.Grand XOR Counting Problem Challenge
    Description给一个数组\({a_i},i=1,\cdots,n\),对\(j=0,1,\cdots,m-1\),计算其中有多少个大小为\(k\)的子序列满足其异或和为\(j\)。\(n\leq10^5\)$m\leq65536$Solution首先答案是\[[y^k]\prod_{i=1}^n(1+x^{a_i}y)\]这里对\(y\)做的是多项式乘法,对\(x\)......
  • CF1955G GCD on a grid 题解
    洛谷链接我们暴力枚举可能的答案\(k\),然后跑一边dp。设\(f_{i,j}\)表示在格子\((i,j)\)是否可以满足有一条路径可以到达该格子且该格子是否为\(k\)的倍数,递推式即为\(f_{i,j}=(k\mida_{i,j}\operatorname{and}(f_{i-1,j}\operatorname{or}f_{i,j-1}))\)最后的答......
  • GCD和LCM
    GCD(最大公约数)的性质唯一性:对于任意两个非零整数 a 和 b,它们的最大公约数是唯一的。非负性:GCD总是非负的,即 gcd(a,b)≥0。交换性:gcd(a,b)=gcd(b,a)。结合性:gcd(a,gcd(b,c))=gcd(gcd(a,b),c)。分配性:gcd(ka,kb)=k*gcd(a,b),其中 k 是正整数......
  • #1118 - Row size too large. The maximum row size for the used table type, not co
    这个问题表示在MySQL中,表的一行数据大小超过了最大限制65535字节。这通常是因为表中的某些字段过长导致的。下面是一些解决方法:调整字段类型:将一些较大的字段改为TEXT或BLOB类型。这些类型的存储方式不同于普通字段,可以避免占用过多的行内空间。拆分字段:如果某个字段包含多......
  • 题解:CF2009D Satyam and Counting
    比较容易观察的一道题,但是场上不开longlong见祖宗了。由于这题的\(x\)最大值比较小,所以我们可以直接存每个坐标是否有点。有两种三角形符号条件:存在两个点\((x,0),(x,1)\),可以观察到任意的其它点都可以成为第三点。有三个点为\((x,0),(x+1,1),(x+2,0)\)或\((x,1),(x+1......
  • P4778 Counting Swaps
    题意:给定一个\(1\simn\)的排列\(a\)。每次可以选两个位置\(i,j\),耗费\(1\)的代价交换\(a_i,a_j\)。问使得\(a\)升序排列的最小代价是多少,以及方案数。\(1\len\le10^5\)。求最小代价:连边\(i\rightarrowa_i\),得到若干个环。一个大小为\(x\)的环需要\(x-1\)次操作......
  • Interval GCD(单点修改线段树)
    细节不少//根据更相减损法gcd(x,y)=gcd(x,y-x)//推广到三项为gcd(x,y,z)=gcd(x,y-x,z-y)//可以推广到n项#include<bits/stdc++.h>usingnamespacestd;#definexfirst#defineysecondtypedefpair<int,int>PII;typedeflonglongll;typedefunsignedlonglong......
  • BFA507 Accounting and Accountability for Decision
    BFA507AccountingandAccountabilityforDecisionMaking-Sem2,2024AssessmentTask2:OralpresentationDue: Week10-Friday,4thOctober2024at5.00pmILOsAddressed: ILO1,ILO2Maximumlength/format: 5-minutevideopresentationincluding:Powerpo......
  • Building Accounting Information System using MS Access
    DatabaseAssignment(Fall2024)BuildingAccountingInformationSystemusingMSAccess(100marks)allaccounts’beginningbalancesarezeroSPELimitedsellsdifferentkindsofsmartphonesthatitpurchasesfromdifferentmanufacturers.Itscustomer......
  • PAT甲级-1115 Counting Nodes in a Binary Search Tree
    题目 题目大意给定节点个数,以及每个节点的值,要求构造一棵二叉排序(搜索)树,并按照规定格式输出最后一层和倒数第二层的节点个数。思路二叉排序树的构造方法是递归,但思路类似于二分查找。逐个将n个节点插入到二叉排序树中,插入完成也就构造完成了。插入节点时,如果该节点值大于......