cd1101d 樹形dp

cd1101d 簡單dp

連接

codeforcesc++

思路

全部數的質因數存下來,最多6個。
而後\(f[i][j][0/1]\)表示i子樹內鏈gcd爲j的i是否爲鏈頭。
暴力轉移就好了spa

代碼

#include <bits/stdc++.h>
using namespace std;
const int _=2e5+7,N=2e5;
int n,pri[_],vis[_],cnt;
vector<int> G[_],dsr[_];
unordered_map<int,int> id[_];
void Euler() {
    for(int i=2;i<=N;++i) {
        if(!vis[i]) {
            pri[++cnt]=i;
            for(int j=i+i;j<=N;j+=i) vis[j]=1;
        }
    }
}
int f[_][7][2],ans=0;
void dfs(int u,int fa) {
    for(int i=0;i<(int)dsr[u].size();++i) f[u][i][0]=f[u][i][1]=1;
    int las[7]={};
    for(auto v:G[u]) {
        if(v==fa) continue;
        dfs(v,u);
        for(auto x:dsr[u]) {
            if(id[v].count(x)) {
                int a=id[u][x],b=id[v][x];
                f[u][a][1]=max(f[u][a][1],f[v][b][0]+las[a]+1);
                las[a]=max(las[a],f[v][b][0]);
                f[u][a][0]=max(f[u][a][0],f[v][b][0]+1);
            }
        }
    }
    for(int i=0;i<(int)dsr[u].size();++i) ans=max(ans,f[u][i][1]);
}
int main() {
    // freopen("a.in","r",stdin);
    Euler();scanf("%d",&n);
    for(int i=1,val,js;i<=n;++i) {
        scanf("%d",&val),js=0;
        for(int j=1;pri[j]*pri[j]<=cnt;++j) {
            if(val%pri[j]==0) {
                dsr[i].push_back(pri[j]),id[i][pri[j]]=js++;
                while(!(val%pri[j])) val/=pri[j];
            }
        } if(val!=1) dsr[i].push_back(val),id[i][val]=js++;
    }
    for(int i=1,u,v;i<n;++i) {
        scanf("%d%d",&u,&v);
        G[u].push_back(v),G[v].push_back(u);
    }
    dfs(1,0);
    cout<<ans<<"\n";
    return 0;
}
相關文章
相關標籤/搜索