容易想到,选的点应该是和\(1\)连通的连通块。最后的答案是\(a[1]\)乘以\(a[1]\)的因子。
所以我们枚举\(a[1]\)的因子,然后判断是否能让所有点都变成\(a[1]\)的因子的倍数。我们容易发现,其实对于每个点而言,一次选中操作都相当于把它的幂次翻倍。
于是我们可以预处理出\(u\)变成\(v\)的倍数需要翻几倍,然后做树上前缀和,就可以求出要变化多少个点了。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 205000;
int n,k;
int a[maxn],b[maxn];
vector<int> g[maxn],res[maxn];
vector <int> factor[1030];
int ok[maxn],dep[maxn];
int sta[maxn];
int gd[1030][1030];
void dfs(int now,int pa,int dp){
dep[now] = dp;
for(auto x:g[now]){
if(x == pa) continue;
dfs(x,now,dp+1);
}
}
void dfs2(int now,int pa){
sta[dep[now]] = now;
for(auto x:g[now]){
if(x == pa) continue;
dfs2(x,now);
}
for(auto z:res[now]){
ok[sta[z]] = 1;
}
sta[dep[now]] = 0;
}
void dfs3(int now,int pa){
for(auto x:g[now]){
if(x == pa) continue;
dfs3(x,now);
ok[now] |= ok[x];
}
}
int check(int mul){
for(int i=1;i<=n;i++) {ok[i] = 0;res[i].clear();}
for(int i=1;i<=n;i++) b[i] = __gcd(a[i],mul);
for(int i=1;i<=n;i++){
if(gd[b[i]][mul] == 0) return false;
int tms = gd[b[i]][mul];
/*while(dt != mul){
tms++;
dt = dt*dt;
dt = __gcd(dt,mul);
}*/
//paint(i,tms);
if(tms > dep[i]) return false;
res[i].push_back(tms);
}
dfs2(1,0);
dfs3(1,0);
int cnt = 0;
for(int i=1;i<=n;i++){
if(ok[i]) cnt ++;
}
if(cnt > k) return false;
else return true;
}
int dpi(int u,int v){
if(u == v) return 1;
if(gd[u][v]) return gd[u][v];
else{
u = u*u;
u = __gcd(u,v);
return dpi(u,v)+1;
}
}
int pri[1050],flag[1050];
int main(){
for(int i=2;i<=1000;i++){
for(int j=1;j*i<=1000;j++) factor[i*j].push_back(i);
}
for(int i=2;i<=1000;i++){
if(!flag[i]){
pri[i] = i;
for(int j=2;j*i<=1000;j++){
if(!flag[i*j]) pri[i*j] = i;
flag[i*j] = 1;
}
}
}
for(int i=2;i<=1000;i++){
for(int j=1;j*i<=1000;j++){
int pp = j,ys = 1;
while(pp != 1){
int po = pri[pp];
if(i%po) ys = 0;
pp /= pri[pp];
}
if(ys) gd[i][i*j] = dpi(i,i*j);
}
}
int t; cin >> t;
while(t--){
cin >> n >> k;
for(int i=1;i<=n;i++) g[i].clear();
for(int i=1;i<=n;i++) cin >> a[i];
for(int i=1;i<n;i++){
int u,v; cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1,0,1);
int ans = a[1];
for(auto mul:factor[a[1]]){
if(check(mul)) ans = max(ans,a[1]*mul);
}
cout<<ans<<endl;
}
return 0;
}
标签:return,Maximizing,CF1778F,int,auto,pa,maxn,now,Root
From: https://www.cnblogs.com/Menhera/p/17086937.html