CF990G-GCD Counting【dfs】
生活随笔
收集整理的這篇文章主要介紹了
CF990G-GCD Counting【dfs】
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
正題
題目鏈接:https://www.luogu.com.cn/problem/CF990G
題目大意
給出一棵有點權的樹,對于每個kkk求有多條路徑的點權gcdgcdgcd為kkk
1≤n≤2×105,1≤ai≤2×1051\leq n\leq 2\times 10^5,1\leq a_i\leq 2\times 10^51≤n≤2×105,1≤ai?≤2×105
解題思路
開始以為要莫反,后來發現不用。
首先gcdgcdgcd之間拆倍數,設fif_ifi?表示點權都是iii的倍數的路徑條數,這個用一個vectorvectorvector存然后暴力枚舉iii加點每次dfsdfsdfs出每個聯通塊的大小就好了。
之后倒序枚舉iii,再枚舉它的倍數ikikik,然后fi?=fikf_i-=f_{ik}fi??=fik?,這樣就自動容斥,用不上莫比烏斯反演了。
時間復雜度O(∑i=1nσ0(ai)+nlog?n)O(\sum_{i=1}^n\sigma_0(a_i)+n\log n)O(∑i=1n?σ0?(ai?)+nlogn)
code
#include<cstdio> #include<cstring> #include<algorithm> #include<vector> #define ll long long using namespace std; const ll N=2e5+10; ll n,w[N],v[N],f[N]; vector<ll> p[N],G[N]; //void Prime(){ // mu[1]=1; // for(ll i=2;i<N;i++){ // if(!v[i])v[i]=1,pri[++cnt]=i,mu[i]=-1; // for(ll j=1;j<=cnt&&i*pri[j]<N;j++){ // v[i*pri[j]]=1; // if(i%pri[j]==0)break; // mu[i*pri[j]]=-mu[i]; // } // } // return; //} ll Add(ll x,ll fa,ll k){v[x]=k;ll siz=0;for(ll i=0;i<G[x].size();i++){ll y=G[x][i];if(y==fa||w[y]%k)continue;siz+=Add(y,x,k);}return siz+1; } signed main() {scanf("%lld",&n);for(ll i=1;i<=n;i++){scanf("%lld",&w[i]);p[w[i]].push_back(i);}for(ll i=1;i<n;i++){ll x,y;scanf("%lld%lld",&x,&y);G[x].push_back(y);G[y].push_back(x);}for(ll i=1;i<=2e5;i++)for(ll j=i;j<=2e5;j+=i)for(ll k=0;k<p[j].size();k++){ll x=p[j][k];if(v[x]==i)continue;ll siz=Add(x,x,i);f[i]+=siz*(siz+1)/2;}for(ll i=2e5;i>=1;i--)for(ll j=2*i;j<=2e5;j+=i)f[i]-=f[j];for(ll i=1;i<=2e5;i++)if(f[i])printf("%lld %lld\n",i,f[i]);return 0; }總結
以上是生活随笔為你收集整理的CF990G-GCD Counting【dfs】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ps中怎么使用图层蒙版(ps怎么使用图层
- 下一篇: 烽火安卓版下载(烽火安卓)