zoukankan      html  css  js  c++  java
  • CF1101D GCD Counting

    CF1101D GCD Counting 

    又被trick了

    不用什么点分治

    直接树形dp即可

    开始的想法:

    f[x][j]x为根的子树gcd至少为j(j是x的一个约数)的最长链

    然后对y合并。类似于树的直径

    但是复杂度还是很大的。。。

    这个题的关键是:我们只关心gcd是不是1,并不关心gcd是什么!

    gcd不是1,意味着一定有公共质因子!

    而质因子个数非常少

    可以f[x][j]表示,x为根的子树,往下走,公共质因子为j的最长链

    然后甚至可以暴力合并!

    显然最优解可以被处理到!

    代码:

    #include<bits/stdc++.h>
    #define reg register int
    #define il inline
    #define numb (ch^'0')
    using namespace std;
    typedef long long ll;
    il void rd(int &x){
        char ch;x=0;bool fl=false;
        while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
        for(x=numb;isdigit(ch=getchar());x=x*10+numb);
        (fl==true)&&(x=-x);
    }
    namespace Miracle{
    const int N=2e5+5;
    vector<int>p[N],f[N];
    int n;
    int ans;
    struct node{
        int nxt,to;
    }e[2*N];
    int hd[N],cnt;
    void add(int x,int y){
        e[++cnt].nxt=hd[x];
        e[cnt].to=y;
        hd[x]=cnt;
    }
    void dfs(int x,int fa){
        for(reg i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;
            if(y==fa) continue;
            dfs(y,x);
            for(reg j=0;j<p[x].size();++j){
            //    cout<<" j "<<p[x][j]<<endl;
                for(reg k=0;k<p[y].size();++k){
                //    cout<<" k "<<p[y][k]<<endl;
                    if(p[x][j]==p[y][k]){
                        ans=max(ans,f[x][j]+f[y][k]);
                        f[x][j]=max(f[x][j],f[y][k]+1);
                    }
                }
            }
        }
    }
    void div(int x,int id){
        for(reg i=2;(ll)i*i<=x;++i){
            if(x%i==0){
                p[id].push_back(i);
                f[id].push_back(1);
                while(x%i==0) x/=i;
            }
        }
        if(x>1){
            p[id].push_back(x);
            f[id].push_back(1);
        }
    }
    int main(){
        rd(n);int x;
        bool flag=false;
        for(reg i=1;i<=n;++i){
            rd(x);
            if(x!=1) flag=true;
            div(x,i);
        }
        if(!flag){
            puts("0");return 0;
        }
        ans=1;
        int y;
        for(reg i=1;i<=n-1;++i){
            rd(x);rd(y);
            add(x,y);add(y,x);
        }
        dfs(1,0);
        printf("%d",ans);
        return 0;
    }
    
    }
    signed main(){
        Miracle::main();
        return 0;
    }
    
    /*
       Author: *Miracle*
       Date: 2019/1/17 19:37:47
    */

    总结:
    其实有些时候,题目很麻烦

    但是实际上可以简化条件,想想我们关心什么

  • 相关阅读:
    AI CV 会议2018
    ubuntu 更改默认亮度
    ubuntu安装latex
    过滤文件代码 python
    ubuntu安装pycharm桌面快捷方式
    Ubuntu 14.04 鼠标消失解决方案
    ffmpeg常用命令
    FFMPEG 在ubuntu下的安装与使用
    pragma once
    chrono--高精度计时
  • 原文地址:https://www.cnblogs.com/Miracevin/p/10284269.html
Copyright © 2011-2022 走看看