codeforces 1210D Kamil and Making a Stream(数论)

题意:

给出一棵树,有 n n n个节点,每个节点有一个点权,设 f ( u , v ) f(u,v) f(u,v) 表示 u u u v v v 路径上所有点权的 g c d gcd gcd ,且 u u u v v v的祖先节点,求 ∑ f ( u , v ) \sum f(u,v) f(u,v)

题解:

因为连续的 g c d gcd gcd 具有单调性,每次要么不变,要么至少除2,即 l o g ( 1 e 12 ) log(1e12) log(1e12) ,那么一条链上 g c d gcd gcd的值最多只有 40 40 40个左右 ,因此父亲节点可以暴力将 g c d gcd gcd传递给儿子节点,然后统计每个 g c d gcd gcd的个数即可。

代码:

#pragma GCC diagnostic error "-std=c++11"
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
#include<set>
#include<ctime>
#define iss ios::sync_with_stdio(false)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int,int> pii;
const int mod=1e9+7;
const int MAXN=2e5+5;
const int inf=0x3f3f3f3f;
ll w[MAXN];
struct node
{
    int to;
    int next;
    /* data */
}e[MAXN<<1];
int head[MAXN];
int cnt=0;
ll ans=0;
void add(int u,int v)
{
    e[cnt].to=v;
    e[cnt].next=head[u];
    head[u]=cnt++;
}
void dfs(int u,int f,map<ll,int>mp)
{
    mp[w[u]]++;
    map<ll,int>now;
    for(auto i:mp)
    {
        ll gd=__gcd(i.first,w[u]);
        now[gd]+=i.second;
        ans=(ans+gd*i.second%mod)%mod;        
    }
    for(int i=head[u];i!=-1;i=e[i].next)
    {
        int v=e[i].to;
        if(v==f) continue;
        dfs(v,u,now);
    }
}
int main()
{
    memset(head,-1,sizeof head);
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>w[i];
    }
    for(int i=1;i<=n-1;i++){
        int u,v;
        cin>>u>>v;
        add(u,v);
        add(v,u);
    }
    map<ll,int>mp;
    dfs(1,0,mp);
    cout<<ans<<endl;
}
posted @ 2021-07-20 20:24  TheBestQAQ  阅读(42)  评论(0)    收藏  举报