cf 990G GCD Counting (莫比乌斯反演 并查集)

990G

给你一棵树,问你有多少个点对(x,y)(x\(\leq\)y),使得(x,y)简单路径上的点权值的\(gcd\)为\(i\),对于\(i\in [1,200000]\)输出点对数目。

这题没有做出来,主要还是莫比乌斯反演时间太长不熟悉了。同时统计点对的技巧也自己没有想出来,实在是不应该。

我们设\(h(i)\)是有多少个点对(x,y)(x\(\leq\)y),使得(x,y)简单路径上的点权值的\(gcd\)为\(i\)的倍数的答案。于是有\(h(i)=\sum_{i=1}^{\lfloor maxa/i \rfloor} ans(k\cdot i)\)。即\(ans(i)=\sum_{k=1}^{\lfloor maxa/i \rfloor} h(k\cdot i)\mu(k)\)。

于是我们就要统计\(h(i)\)。这个怎么统计呢,就是要有这样的简单路径存在那肯定是有一整个联通块,这个联通块里的点的点权全部是\(i\)的倍数,我们就要找这些联通块出来。把所有\(i\)的倍数的点拿出来,并查集合并大小到父亲,然后统计所有的父亲对答案的贡献即可。

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

inline int readInt() {
  char c; int tmp=0,x=1; c=getchar();
  while(c>‘9‘ || c<‘0‘) {if(c==‘-‘) x=-1; c=getchar();}
  while(c>=‘0‘ && c<=‘9‘) {tmp=tmp*10+c-‘0‘; c=getchar();}
  return tmp*x;
}

const int maxN=200000+10;

int a[maxN],n;
vector<int > g[maxN];
void addEdge(int u,int v) {
  g[u].push_back(v); g[v].push_back(u);
}

bool vis[maxN];
int pri[maxN],tot=0,mu[maxN];
void sieve() {
  mu[1]=1;
  for(int i=2;i<maxN;i++) {
    if(!vis[i]) pri[++tot]=i,mu[i]=-1;
    for(int j=1;j<=tot && pri[j]*i<maxN;j++) {
      vis[pri[j]*i]=true;
      if(i%pri[j]==0) {
        mu[pri[j]*i]=0;
        break;
      }
      mu[pri[j]*i]=-mu[i];
    }
  }
}

int Fa[maxN];
void dfs(int v,int fa) {
  Fa[v]=fa;
  for(int i=0;i<(int)g[v].size();i++) {
    int u=g[v][i];
    if(u!=fa) dfs(u,v);
  }
}

int siz[maxN],f[maxN];
int getFather(int x) {
  return x==f[x]?f[x]:f[x]=getFather(f[x]);
}
void mergeUnion(int u,int v) {
  int fu=getFather(u),fv=getFather(v);
  if(fu==fv) return;
  else {
    if(siz[fu]>siz[fv]) swap(fu,fv);
    siz[fv]+=siz[fu];
    f[fu]=fv;
  }
}

vector<int > hav[maxN],all;
ll h[maxN],ans[maxN];
int main() {
  sieve();
  memset(vis,0,sizeof(vis));
  n=readInt();
  for(int i=1;i<=n;i++) a[i]=readInt(),hav[a[i]].push_back(i);
  int u,v;
  for(int i=1;i<=n-1;i++) {
    u=readInt(),v=readInt();
    addEdge(u,v);
  }
  dfs(1,-1);
  for(int i=1;i<=200000;i++) {
    for(int k=0;k<(int)all.size();k++) siz[all[k]]=0,f[all[k]]=0,vis[all[k]]=false;
    all.clear();
    for(int j=i;j<=200000;j+=i) {
      for(int k=0;k<(int)hav[j].size();k++) {
        siz[hav[j][k]]=1,f[hav[j][k]]=hav[j][k];
        all.push_back(hav[j][k]);
      }
    }
    for(int k=0;k<(int)all.size();k++) {
      v=all[k];
      if(Fa[v]!=-1 && a[Fa[v]]%i==0) mergeUnion(Fa[v],v);
    }
    for(int k=0;k<(int)all.size();k++) {
      v=all[k];
      if(!vis[u=getFather(v)]) h[i]+=1ll*siz[u]*(siz[u]+1)/2,vis[u]=true;
    }
  }
  for(int i=1;i<=200000;i++) {
    for(int j=1;j<=(200000/i);j++) {
      ans[i]+=h[j*i]*1ll*mu[j];
    }
  }
  for(int i=1;i<=200000;i++) {
    if(ans[i]>0) printf("%d %I64d\n",i,ans[i]);
  }
  return 0;
}

原文地址:https://www.cnblogs.com/darkroome/p/9201674.html

时间: 2024-10-29 03:12:10

cf 990G GCD Counting (莫比乌斯反演 并查集)的相关文章

【HDU1695】GCD(莫比乌斯反演)

[HDU1695]GCD(莫比乌斯反演) 题面 题目大意 求\(a<=x<=b,c<=y<=d\) 且\(gcd(x,y)=k\)的无序数对的个数 其中,你可以假定\(a=c=1\) 所有数都\(<=100000\) 数据组数\(<=3000\) 题解 莫比乌斯反演 作为一道莫比乌斯反演的题目 首先我们要迈出第一步 如果有\(gcd(x,y)=k\) 那么,我们就有\(gcd(\frac{x}{k},\frac{y}{k})=1\) 所以,现在问题相当于转化为了求 \(

【BZOJ2820】YY的GCD(莫比乌斯反演)

[BZOJ2820]YY的GCD(莫比乌斯反演) 题面 讨厌权限题!!!提供洛谷题面 题解 单次询问\(O(n)\)是做过的一模一样的题目 但是现在很显然不行了, 于是继续推 \[ans=\sum_{d=1}^n[d\_is\_prime]\sum_{i=1}^{n/d}[\frac{n}{id}][\frac{m}{id}]\] 老套路了 令\(T=id\) \[ans=\sum_{T=1}^{n}[\frac{n}{T}][\frac{m}{T}]\sum_{d|T}[d\_is\_prim

hdu_1695: GCD 【莫比乌斯反演】

题目链接 这题求[1,n],[1,m]gcd为k的对数.而且没有顺序. 设F(n)为公约数为n的组数个数 f(n)为最大公约数为n的组数个数 然后在纸上手动验一下F(n)和f(n)的关系,直接套公式就好了.注意要删去重复的. 关于 莫比乌斯反演 的结论 #include<bits/stdc++.h> using namespace std; typedef long long LL; const int maxn=1e6; int prime[maxn+5]; bool check[maxn+

acdream 1148 GCD SUM 莫比乌斯反演 ansx,ansy

GCD SUM Time Limit: 8000/4000MS (Java/Others)Memory Limit: 128000/64000KB (Java/Others) SubmitStatisticNext Problem Problem Description 给出N,M执行如下程序:long long  ans = 0,ansx = 0,ansy = 0;for(int i = 1; i <= N; i ++)   for(int j = 1; j <= M; j ++)     

HDU 1695 GCD (莫比乌斯反演)

传送门 GCD Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 9749    Accepted Submission(s): 3648 Problem Description Given 5 integers: a, b, c, d, k, you're to find x in a-b, y in c-d that GCD(x, y)

HDU 1695 GCD 【莫比乌斯反演例题】

GCDTime Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 4291 Accepted Submission(s): 1502   Problem DescriptionGiven 5 integers: a, b, c, d, k, you're to find x in a...b, y in c...d that GCD(x, y) = k.

hdu1695 GCD(莫比乌斯反演)

题意:求(1,b)区间和(1,d)区间里面gcd(x, y) = k的数的对数(1<=x<=b , 1<= y <= d). 知识点: 莫比乌斯反演/*12*/ 线性筛求莫比乌斯反演函数: void Init() { memset(vis,0,sizeof(vis)); mu[1] = 1; cnt = 0; for(int i=2; i<N; i++) { if(!vis[i]) { prime[cnt++] = i; mu[i] = -1; } for(int j=0;

P2257 YY的GCD (莫比乌斯反演)

[题目链接] https://www.luogu.org/problemnew/show/P2257 // luogu-judger-enable-o2 /* ----------------------- [题解] https://www.luogu.org/blog/peng-ym/solution-p2257 [莫比乌斯反演] http://www.cnblogs.com/peng-ym/p/8647856.html [整除分块] http://www.cnblogs.com/peng-y

CF 500 B. New Year Permutation 并查集

User ainta has a permutation p1, p2, ..., pn. As the New Year is coming, he wants to make his permutation as pretty as possible. Permutation a1, a2, ..., an is prettier than permutation b1, b2, ..., bn, if and only if there exists an integer k (1 ≤ k