zoukankan      html  css  js  c++  java
  • HDU4670 cube number on a tree(点分治+三进制加法)

    The country Tom living in is famous for traveling. Every year, many tourists from all over the world have interests in traveling there. 
    There are n provinces in the country. According to the experiences from the tourists came before, every province has its own preference value. A route’s preference value from one province to another is defined as the product of all the preference value of the provinces on the route. It’s guaranteed that for each two provinces in the country there is a unique route from one to another without passing any province twice or more. 
    Tom is a boy crazy about cube number. A cube number is a positive integer whose cube root is also an integer. He is planning to travel from a province to another in the summer vacation and he will only choose the route with the cube number preference value. Now he want to know the number of routes that satisfy his strange requirement.

    Input

    The input contains several test cases, terminated by EOF. 
    Each case begins with a number n ( 1 ≤ n ≤ 50000), the number of the provinces. 
    The second line begins with a number K (1 ≤ K ≤ 30), and K difference prime numbers follow. It’s guaranteed that all the preference number can be represented by the product of some of this K numbers(a number can appear multiple times). 
    The third line consists of n integer numbers, the ith number indicating the preference value P i(0 ≤ P i ≤ 10 15) of the i-th province. 
    Then n - 1 lines follow. Each line consists of two integers x, y, indicating there is a road connecting province x and province y. 

    Output

    For each test case, print a number indicating the number of routes that satisfy the requirement.Sample Input

    5
    3 2 3 5
    2500 200 9 270000 27
    4 2
    3 5
    2 5
    4 1

    Sample Output

    1


    题解:


    题意:给你一棵树,给你一些素数,给你每个点一个权值且每个权值均可由这些素数组成。现在定义任意任意两点的价值为他们路径上的权值相乘。求这样的点对的权值为立方数的个数
    如果直接求得话会超int64,不可行
    由立方数的性质可得,一个数可有素数组成,对于这些素数可以分解为这些素数相乘的形式如,24=(2^3)*(3^1);如果是立方数的话那么他的各进制对3取余都为0.股24可写成01这种三进制形式
    对于这些权值的乘法可有三进制想加可得。
    接下来就是树的分治了
    当然这里可以先求出一条子树上的各个点的权值乘积,然后和根节点和其他字树比较看是否可以互补那么就找到一对
    可用map容器实现。因为他重点是比较到根节点和其他子树是否可以互补,进而递归下去,求出每个子树的这样的点对


    参考代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define fi first
    #define se second
    #define pii pair<int,int>
    #define pil pair<int,ll>
    #define mkp make_pair
    #define pb push_back
    const int INF=0x3f3f3f3f;
    const ll inf=0x3f3f3f3f3f3f3f3fll;
    inline ll read()
    {
        ll x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
        return x*f;
    }
    const int maxn=1e5+10;
    ll n,k,head[maxn],tot,root,siz[maxn];
    ll h[maxn][40],pri[40],fa[maxn],mx[maxn],S;
    ll dep,ch[maxn][40],fp[maxn],minn,nn;
    bool vis[maxn];
    map<ll,ll> mp;
    struct Edge{
        int v,nxt;
    } edge[maxn<<1];
    
    inline void Init()
    {
        tot=0;
        memset(head,-1,sizeof(head));
        memset(h,0,sizeof(h));
        memset(mx,0,sizeof(mx));
        memset(siz,0,sizeof(siz));
        memset(vis,false,sizeof(vis));
    }
    
    inline void AddEdge(ll u,ll v)
    {
        edge[tot].v=v;
        edge[tot].nxt=head[u];
        head[u]=tot++;
    }
    
    inline void dfs1(ll u,ll fa)
    {
        nn++;
        for(int e=head[u];~e;e=edge[e].nxt)
        {
            ll v=edge[e].v;
            if(v==fa||vis[v]) continue;
            dfs1(v,u);
        }
    }
    
    inline void GetRoot(ll u,ll fa)
    {
        siz[u]=1;
        ll tit=0;
        for(ll e=head[u];~e;e=edge[e].nxt)
        {
            ll v=edge[e].v;
            if(v==fa||vis[v]) continue;
            GetRoot(v,u);
            siz[u]+=siz[v];
            tit=max(tit,siz[v]);
        }
        tit=max(tit,nn-siz[u]);
        if(tit<minn) minn=tit,root=u;
    }
    inline void dfs2(ll u,ll fa)
    {
        //cout<<"dfs2"<<endl;
        if(fa==-1)
        {
             for(ll i=1;i<=k;++i)
                ch[dep][i]=h[u][i];
        }
        else
        {
            ll e=fp[fa];
            for(ll i=1;i<=k;++i)
                ch[dep][i]=(h[u][i]+ch[e][i])%3;
        }
        fp[u]=dep++;
        for(ll e=head[u];~e;e=edge[e].nxt)
        {
            ll v=edge[e].v;
            if(v!=fa&&!vis[v]) dfs2(v,u);
        }
    }
    
    inline ll work(ll u)
    {
        ll s1=0,ans=0;
        mp.clear();
        for(ll i=1;i<=k;++i) s1=s1*3+h[u][i];
        if(s1==0) ans++;
        mp[s1]=1;
        for(ll e=head[u];~e;e=edge[e].nxt)
        {
            ll v=edge[e].v;
            if(vis[v]) continue;
            dep=0;dfs2(v,-1);
            for(ll i=0;i<dep;++i)
            {
                s1=0;
                for(ll j=1;j<=k;++j)
                    s1=s1*3+(3-ch[i][j])%3;
                ans+=mp[s1];
            }
            for(ll i=0;i<dep;++i)
            {
                s1=0;
                for(ll j=1;j<=k;++j)
                    s1=s1*3+(ch[i][j]+h[u][j])%3;
                mp[s1]++;
            }
        }
        return ans;
    }
    
    inline ll dfs(ll u)
    {
        nn=0,minn=inf;
        dfs1(u,-1);
        GetRoot(u,-1);
        vis[root]=1;
        ll ans=work(root);
        for(ll e=head[root];~e;e=edge[e].nxt)
        {
            ll v=edge[e].v;
            if(vis[v]) continue;
            ans+=dfs(v);
        }
        return ans;
    }
    
    int main()
    {
        while(~scanf("%lld",&n))
        {
            Init();
            k=read();
            for(ll i=1;i<=k;++i) pri[i]=read();
    
            for(ll i=1;i<=n;++i)
            {
                ll kk,val=read();
                for(ll j=1;j<=k;++j)
                {
                    kk=0;
                    while(val%pri[j]==0)
                    {
                        ++kk;
                        val/=pri[j];
                        kk%=3;
                    }
                    h[i][j]=kk;
                }
            }
            for(ll i=1;i<n;++i)
            {
                ll x,y;
                x=read();y=read();
                AddEdge(x,y);AddEdge(y,x);
            }
            //cout<<"1"<<endl;
            printf("%lld
    ",dfs(1));
        }
    
        return 0;
    }
    View Code
  • 相关阅读:
    数据挖掘、机器学习、人工智能学习笔记
    SQL Server 定价及授权方式
    数据仓库的架构以及数据分层【转】
    java各历史版本官网下载
    VMware三个版本workstation、server、esxi的区别
    顶级项目孵化的故事系列——Kylin的心路历程【转】
    Oracle数据库学习笔记
    数据仓库学习笔记
    多维数据库介绍【转】
    ROLAP、MOLAP和HOLAP区别
  • 原文地址:https://www.cnblogs.com/csushl/p/11349137.html
Copyright © 2011-2022 走看看