E. You
首先我们假设每个节点有个点权,点权是儿子的数量。
一个点可以和他的父亲所要权值1(先删去自己,再删去父亲),并且此操作不可逆。于是dfs从叶子节点一次递推即可得出某个kkk是否能作为gcd\gcdgcd。
由于上述“权值交换”的过程只会变化1,并且权值和一定是n-1,只需要枚举n-1的约数一一dfs递推判断即可。
注意:最后需要容斥一下重复计算的情况
upd:我们在dfs时并没有直接考虑gcd\gcdgcd,而是通过考虑点权是否是gcd\gcdgcd的倍数,显然如果一个是6的倍数,自然也是2的倍数,但gcd要求我们是最大公约数,所以由于2的答案是依附于6的基础上,需要减去。
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
template <class T=int> T rd()
{T res=0;T fg=1;char ch=getchar();while(!isdigit(ch)) {if(ch=='-') fg=-1;ch=getchar();}while( isdigit(ch)) res=(res<<1)+(res<<3)+(ch^48),ch=getchar();return res*fg;
}
const int N=100010,mod=998244353;vector<int> g[N];
int a[N],n;
ll ans[N];
bool dfs(int u,int fa,int val)
{for(auto v:g[u]){if(v==fa) continue;if(!dfs(v,u,val)) return 0;}if(a[u]%val==0){if(fa) a[fa]++;return 1;}if((a[u]+1)%val==0&&fa) return 1;return 0;
}
void init()
{for(int i=1;i<=n;i++) ans[i]=0;for(int i=1;i<=n;i++) a[i]=0;for(int i=1;i<=n;i++) g[i].clear();
}
int main()
{int Tc=rd();while(Tc--){init();n=rd();for(int i=1;i<n;i++){int u=rd(),v=rd();g[u].push_back(v);g[v].push_back(u);}for(int i=1;i<n;i++)if((n-1)%i==0){if(i==1) {ans[1]=1;for(int i=1;i<n;i++) ans[1]=ans[1]*2%mod;continue;}for(int i=1;i<=n;i++) a[i]=0;if(dfs(1,0,i)) ans[i]++;}for(int i=n;i>=1;i--)for(int j=2;i*j<=n;j++)ans[i]=(ans[i]-ans[i*j]+mod)%mod;for(int i=1;i<=n;i++) printf("%lld%c",ans[i]," \n"[i==n]);}return 0;
}