• [CodeForeces842]Ilya And The Tree解题报告(因数分解)


    传送门:不要戳我QAQ
     
    这道题是昨天晚上模拟赛的第二题。一下子没冷静就写了一坨树剖,没调出来,最后交一个n3的暴力然后爆零了。
    考虑到每个节点的最后答案都是从这个节点到根节点的一条链,并且每个节点都要有答案。所以不应该考虑树链剖分而应该考虑树形dp。
    每个节点最后的答案链都必然交与根节点,这意味着我们的答案有两种情况:取了根节点和没取根节点。没取根节点的情况很好维护,用普通的dfs就搞定了,这里不细解释,不明白看代码就懂了。
    对于取根节点的情况,我们这样考虑,既然取了根节点,那么最后答案必然是根节点权值的因子,因为gcd的第一个数就是根节点的权值。我们维护一个数组num[x],表示我们做树形dp的dfs时,当前结点到根节点的路径上所有节点包含的根节点的因子的个数。简单点说就是,根节点的因子在路上出现的次数。对于一个节点,如果它要取一个答案x,那么x必须满足两个条件,1,该节点权值被x整除,2,x在该节点到根的路上出现了至少depth-1(该节点深度)次。(depth-1)次就能做到去掉一个节点后该值能整除所有节点。
    那么代码实现就很简单了。
    我的代码的分解因子部分写丑了,但因为AC了,就懒地该成sqrt(N)的形式,大家不要学我qwq。
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #define maxn 500005
    using namespace std;
    inline void read(int &x)
    {
        x=0;int f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        x*=f;
    }
    int gcd(int a,int b)
    {
        if(a==0)
            return b;
        if(b==0)
            return a;
        return gcd(b,a%b);
    }
    struct node{
        int nex,to;
    }edge[maxn];
    int head[maxn],tot;
    int N,a[maxn];
    inline void insert(int from,int to)
    {
        edge[++tot].nex=head[from];
        edge[tot].to=to;
        head[from]=tot;
    }
    int dp_nroot[maxn],dp_all[maxn],dp_root[maxn],ans[maxn];
    int p[maxn],id,num[maxn];
    void init()
    {
        int n=a[1]/2;
        for(int i=2;i<=n;i++)
            if(a[1]%i==0)
                p[++id]=i;
        p[++id]=a[1];
    }
    int dept[maxn];
    void dfs(int x,int u)
    {
        dept[x]=dept[u]+1;
        if(x!=1)
            dp_nroot[x]=gcd(dp_nroot[u],a[x]);
        dp_all[x]=gcd(dp_all[u],a[x]);
        for(int i=1;i<=id;i++)
            if(a[x]%p[i]==0)
                num[i]++;
        /*cout<<"NOTE :"<<x<<endl;
        for(int i=1;i<=id;i++)
            cout<<num[i]<<" ";
        cout<<endl;*/
        for(int i=id;i>0;i--)
            if(num[i]>=dept[x]-1)
            {
                dp_root[x]=p[i];
                //cout<<"ROOT NTOE: "<<x<<" "<<p[i]<<endl;
                break;
            }
                
        ans[x]=max(dp_root[x],max(dp_nroot[x],dp_all[x]));
        for(int i=head[x];i;i=edge[i].nex)
            if(edge[i].to^u)    
                dfs(edge[i].to,x);
        for(int i=1;i<=id;i++)
            if(a[x]%p[i]==0)
                num[i]--;
    }
    int main()
    {
        read(N);
        int u,v;
        for(int i=1;i<=N;i++)
            read(a[i]);
        for(int i=1;i<N;i++)
        {
            read(u);
            read(v);
            insert(u,v);
            insert(v,u);
        }
        init();
        //for(int i=1;i<=id;i++)
        //    cout<<p[i]<<" ";
        //cout<<endl;
        dfs(1,1);
        /*for(int i=1;i<=N;i++)
            cout<<dp_all[i]<<" "<<dp_nroot[i]<<" "<<dp_root[i]<<endl;*/
        for(int i=1;i<=N;i++)
            printf("%d ",ans[i]);
    }
     
     
  • 相关阅读:
    正则表达式
    小弟新从csdn搬迁到博客园,欢迎大家关注
    做完牛腩新闻发布系统之后的收获(牛腩总结)
    ValidateRequest="false" 无效
    sql server小技巧-自动添加时间与主键自增长
    css初接触
    Spark的Rpct模块的学习
    插入排序
    选择排序
    冒泡排序
  • 原文地址:https://www.cnblogs.com/sherrlock/p/9647376.html
Copyright © 2020-2023  润新知